Spring Cloud Gateway中提供的默认filter有时不能满足实际的业务需求,因此很多时候需要使用定制的filter。

在Spring Cloud Gateway中,predicate用于定义请求需要满足什么条件才能对它继续进行处理,filter用于定义对请求进行怎样的处理,uri用于定义处理后的请求要转发到什么地址。

filter执行的顺序是有优先级的,优先级越高则在pre阶段执行顺序越靠前,而在post阶段执行顺序越靠后。在Spring Cloud Gateway中会为每个filter设置一个order值,order值越大则优先级越低,order值起小优先级越高。

Spring Cloud Gateway中有两个非常重要的GlobalFilter:

filter名称作用优先级
RouteToRequestUrlFilter生成最终转发到的uri10000
NettyRoutingFilter转发报文Integer.MAX_VALUE

 

 

例如要实现根据特定标识将请求转发到指定uri的功能,则定制的filter的优先级要在RouteToRequestUrlFilter和NettyRoutingFilter之间,下面提供一个例子:

pom.xml

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<maven.compiler.source>1.8</maven.compiler.source>
	<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-webflux</artifactId>
		<version>2.4.4</version>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-gateway</artifactId>
		<version>3.0.2</version>
	</dependency>
</dependencies>

 application.properties

server.port=8070
spring.application.name=gateway_server

# unit: ms
spring.cloud.gateway.httpclient.connect-timeout=10000
spring.cloud.gateway.httpclient.response-timeout=5s

 java代码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@SpringBootApplication
@EnableAutoConfiguration(exclude = { ErrorMvcAutoConfiguration.class })
public class SpringCloudGatewayApplication {
	@Autowired
	private CustomerFilter filter;

	public static void main(String[] args) {
		SpringApplication.run(SpringCloudGatewayApplication.class, args);
	}

	@Bean
	public RouteLocator myRoutes(RouteLocatorBuilder builder) {
		return builder.routes().route(p -> p.path("/**").filters(f -> f.filter(filter)).uri("no://op")).build();
	}

}
import reactor.core.publisher.Mono;

@Component
public class CustomerFilter implements GatewayFilter, Ordered {

	@Override
	public int getOrder() {
		return RouteToRequestUrlFilter.ROUTE_TO_URL_FILTER_ORDER + 1;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		String newUrl = null;
		String serviceName = "";

		List<String> serviceHeaderList = exchange.getRequest().getHeaders().getValuesAsList("serviceName");

		if (serviceHeaderList.contains("s1")) {
			newUrl = "http://127.0.0.1:9090/TestWebApp/testServlet";
			serviceName = "s1";
		} else if (serviceHeaderList.contains("s2")) {
			newUrl = "http://127.0.0.1:9090/TestWebApp/regionServlet?flag=list";
			serviceName = "s2";
		}

		try {
			exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, new URI(newUrl));
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}

		Mono<Void> ret = chain.filter(exchange);

		exchange.getResponse().getHeaders().add("doWork", serviceName + " ok");

		return ret;
	}
}

以上代码中可以看到,会根据请求头中serviceName对应的值转到不同的uri,同时把order的值设置成比RouteToRequestUrlFilter的order的值大1,这样CustomerFilter在pre阶段就会在RouteToRequestUrlFilter之后执行。

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐