SpringCloud源码之API网关Gateway

一、概念:

在微服务架构下,每个微服务都有不同的IP地址和端口,前端在访问时就需要针对每个微服务单独访问,一旦新增或者调整微服务后,前端也需要做同步的修改,非常麻烦,而且为了校验访问请求是合法的,每个微服务都需要都需要做安全校验。引入API网关后,前端就只需要访问API网关就行了,里面的请求转发和一些其他的验权都可以放在API网关里面进行统一处理。因此API网关的职责一是路由功能,根据定义的请求规则和转化的规则,将传入的请求映射到不同的微服务进行处理,另一个职责就是针对请求信息在API网关进行统一验权。SpringCloud Gateway是一款非常优秀性能强劲的API网关。

SpringCloud Gateway接收请求的总入口是DispatcherHandler,有两个非常重要的核心概念,就是路由(Route)和过滤器(Filter)。

1、路由(Route):Route 是网关的基础元素,由 ID、目标 URI、断言、过滤器组成。当请求到达网关时,由 Gateway HandlerMapping 通过断言进行路由匹配(Mapping),当断言为真时,匹配到路由。

Route的定义如下:

arduino 复制代码
public class Route implements Ordered {
	private final String id;
	private final URI uri;
	private final int order;
	private final AsyncPredicate<ServerWebExchange> predicate;
	private final List<GatewayFilter> gatewayFilters;
	private final Map<String, Object> metadata;
	...........
}

在配置文件定义的Route信息在SpringCloud Gateway里面叫做RouteDefinition,其定义如下:

typescript 复制代码
public class RouteDefinition {
	private String id;
	private List<PredicateDefinition> predicates = new ArrayList<>();
	private List<FilterDefinition> filters = new ArrayList<>();
	private URI uri;
	private Map<String, Object> metadata = new HashMap<>();
	private int order = 0;
	...........
}

public class PredicateDefinition {
	private String name;
	private Map<String, String> args = new LinkedHashMap<>();
	............
}

public class FilterDefinition {
	private String name;
	private Map<String, String> args = new LinkedHashMap<>();
	................
}

2、过滤器:过滤器可以在请求到达业务代码之前执行一些业务上的处理。SpringCloud gateway中有两种过滤器,路由过滤器(接口为GatewayFilter)和全局过滤器(接口为GlobalFilter);

路由过滤器GatewayFilter的定义如下:

kotlin 复制代码
public interface GatewayFilter {
	/**
	 * Process the Web request and (optionally) delegate to the next
	 * {@code WebFilter} through the given {@link GatewayFilterChain}.
	 * @param exchange the current server exchange
	 * @param chain provides a way to delegate to the next filter
	 * @return {@code Mono<Void>} to indicate when request processing is complete
	 */
	Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
} 

全局过滤器GlobalFilter的定义如下:

kotlin 复制代码
public interface GlobalFilter {
	/**
	 * Process the Web request and (optionally) delegate to the next
	 * {@code WebFilter} through the given {@link GatewayFilterChain}.
	 * @param exchange the current server exchange
	 * @param chain provides a way to delegate to the next filter
	 * @return {@code Mono<Void>} to indicate when request processing is complete
	 */
	Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

二、使用Demo:

1、引入依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
//由于采用了基于注册中心的动态路由,而注册中心使用的是eureka,因此需要引入eureka的包
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、配置文件application.yml:

yaml 复制代码
spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lowerCaseServiceId: true
      routes:
        #netty 路由过滤器,http或https开头
        - id: app1-route
          uri: http://www.baidu.com
          predicates:
            - Path=/app1/**
          filters:
            #转发请求时去掉1级前缀
            - StripPrefix=1

3、实现Filter:

kotlin 复制代码
@Configuration
public class AccessFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
    return Ordered.HIGHEST_PRECEDENCE;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {  
    //鉴权
    Mono<Void> check = checkAccess(exchange);
    return check != null ? check : chain.filter(exchange);
}

三、总流程:

首先来看一张官网上的SpringCloud Gateway的架构图:

1、客户端发送请求到Spring Cloud Gateway,也就是DispatcherHandler接收了请求,如果Gateway Handler Mapping 判定 这个请求和路由是匹配的,则这个请求会被发送到Gateway Web Handler。

2、Gateway Web Handler通过与该请求匹配的过滤器链执行该请求。

再具体点的流程图:

SpringCloud Gateway API网关的流程:

1、加载路由定义RouteDefinition的集合;

2、将RouteDefinition集合转换为Route实例集合;

3、DispatcherHandler根据URL请求匹配Route;

4、交由WebHandler(FilteringWebHandler)执行过滤器链;

5、执行业务代码,并处理返回结果数据;

下面将分别针对这个流程步骤进行解析。

四、加载路由定义RouteDefinition的集合:

RouteDefinition加载的接口是RouteDefinitionLocator,这个接口有多个实现,最常见的RouteDefinition分别是application.yml定义和从配置中心加载。

RouteDefinition接口的定义只有只有一个方法getRouteDefinitions,代码如下:

csharp 复制代码
public interface RouteDefinitionLocator {
	Flux<RouteDefinition> getRouteDefinitions();
}

1、application.yml定义的路由信息加载RouteDefinition:

比如上面的demo,就是在配置文件application.yml中定义路由信息的,其加载是由PropertiesRouteDefinitionLocator完成的。代码如下:

kotlin 复制代码
public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {
	private final GatewayProperties properties;

	public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
		this.properties = properties;
	}

	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		return Flux.fromIterable(this.properties.getRoutes());
	}
}

@ConfigurationProperties("spring.cloud.gateway")
public class GatewayProperties {	
	private List<RouteDefinition> routes = new ArrayList<>();
	
	................
}

由GatewayProperties类可以看到SpringBoot启动时会将application.yml中定义的spring.cloud.gateway.routes下面的所有的信息都加载到routes中,PropertiesRouteDefinitionLocator直接引用GatewayProperties就可以读取到application.yml中定义的RouteDefinition。

2、从配置中心加载RouteDefinition:

从配置中心加载RouteDefinition是由DiscoveryClientRouteDefinitionLocator完成的。其定义和加载代码如下:

ini 复制代码
public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
	//管理以spring.cloud.gateway.discovery.locator开头的属性定义
	private final DiscoveryLocatorProperties properties;
	
	private final String routeIdPrefix;
	
	//存储注册中心的所有服务实例
	private Flux<List<ServiceInstance>> serviceInstances;

	public DiscoveryClientRouteDefinitionLocator(ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
		this(discoveryClient.getClass().getSimpleName(), properties);
		//通过discoveryClient.getServices和discoveryClient.getInstances获取配置中心中的所有服务实例
		serviceInstances = discoveryClient.getServices().flatMap(service -> discoveryClient.getInstances(service).collectList());
	}
	
	public Flux<RouteDefinition> getRouteDefinitions() {
		.........省略部分代码............

		return serviceInstances.filter(instances -> !instances.isEmpty())				
				.map(instance -> {
					//从注册中心的服务实例信息构造RouteDefinition
					RouteDefinition routeDefinition = buildRouteDefinition(urlExpr, instance);					

					//构造RouteDefinition的断言信息
					for (PredicateDefinition original : this.properties.getPredicates()) {
						PredicateDefinition predicate = new PredicateDefinition();
						predicate.setName(original.getName());
						for (Map.Entry<String, String> entry : original.getArgs().entrySet()) {
							String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry);
							predicate.addArg(entry.getKey(), value);
						}
						routeDefinition.getPredicates().add(predicate);
					}

					//构造RouteDefinition的过滤器链信息
					for (FilterDefinition original : this.properties.getFilters()) {
						FilterDefinition filter = new FilterDefinition();
						filter.setName(original.getName());
						for (Map.Entry<String, String> entry : original.getArgs()
								.entrySet()) {
							String value = getValueFromExpr(evalCtxt, parser,
									instanceForEval, entry);
							filter.addArg(entry.getKey(), value);
						}
						routeDefinition.getFilters().add(filter);
					}

					return routeDefinition;
				});
	}
	
	protected RouteDefinition buildRouteDefinition(Expression urlExpr, ServiceInstance serviceInstance) {
		String serviceId = serviceInstance.getServiceId();
		RouteDefinition routeDefinition = new RouteDefinition();
		routeDefinition.setId(this.routeIdPrefix + serviceId);
		String uri = urlExpr.getValue(this.evalCtxt, serviceInstance, String.class);
		routeDefinition.setUri(URI.create(uri));
		// add instance metadata
		routeDefinition.setMetadata(new LinkedHashMap<>(serviceInstance.getMetadata()));
		return routeDefinition;
	}
}
	
@ConfigurationProperties("spring.cloud.gateway.discovery.locator")
public class DiscoveryLocatorProperties {
	private boolean enabled = false;
	
	private String routeIdPrefix;

	private String includeExpression = "true";

	private String urlExpression = "'lb://'+serviceId";

	private boolean lowerCaseServiceId = false;

	private List<PredicateDefinition> predicates = new ArrayList<>();

	private List<FilterDefinition> filters = new ArrayList<>();
	................
}

1、DiscoveryClientRouteDefinitionLocator的构造函数中,会调用discoveryClient.getServices和discoveryClient.getInstances获取配置中心中的所有服务实例信息保存到serviceInstances中;

2、遍历serviceInstances,buildRouteDefinition依据每一个ServiceInstance构造一个RouteDefinition对象,predicates和filters信息则从DiscoveryLocatorProperties中读取,而DiscoveryLocatorProperties对于predicates和filters集合则只有定义而没有赋值,是不是很好奇他是怎么生成的,看看GatewayDiscoveryClientAutoConfiguration的中的配置就恍然大悟了:

less 复制代码
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
@AutoConfigureAfter(CompositeDiscoveryClientAutoConfiguration.class)
@ConditionalOnClass({ DispatcherHandler.class })
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {
	...........省略部分代码.........
	
	@Bean
	public DiscoveryLocatorProperties discoveryLocatorProperties() {
		DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
		properties.setPredicates(initPredicates());
		properties.setFilters(initFilters());
		return properties;
	}
	
	public static List<PredicateDefinition> initPredicates() {
		ArrayList<PredicateDefinition> definitions = new ArrayList<>();	
		PredicateDefinition predicate = new PredicateDefinition();
		predicate.setName(normalizeRoutePredicateName(PathRoutePredicateFactory.class));
		predicate.addArg("pattern", "'/'+serviceId+'/**'");
		definitions.add(predicate);
		return definitions;
	}
	
	public static List<FilterDefinition> initFilters() {
		ArrayList<FilterDefinition> definitions = new ArrayList<>();
		
		FilterDefinition filter = new FilterDefinition();
		filter.setName(normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
		String regex = "'/' + serviceId + '/(?<remaining>.*)'";
		String replacement = "'/${remaining}'";
		filter.addArg("regexp", regex);
		filter.addArg("replacement", replacement);
		definitions.add(filter);

		return definitions;
	}
}

五、将RouteDefinition集合转换为Route实例集合:

RouteLocator接口用于将RouteDefinition转换为Route实例,这个接口只定义了一个方法getRoutes,代码如下:

csharp 复制代码
public interface RouteLocator {
	Flux<Route> getRoutes();
}

这个接口有三个实现类:CachingRouteLocator,CompositeRouteLocator,RouteDefinitionRouteLocator,这里以RouteDefinitionRouteLocator为例进行分析,代码如下:

kotlin 复制代码
public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
	..........省略部分代码..........

	private final RouteDefinitionLocator routeDefinitionLocator;

	private final ConfigurationService configurationService;

	private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();

	private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();

	private final GatewayProperties gatewayProperties;
	
	public Flux<Route> getRoutes() {
		//将RouteDefinition集合转换为Route实例集合
		Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute);

		return routes.map(route -> {			
			return route;
		});
	}
}

getRoutes中this.routeDefinitionLocator.getRouteDefinitions获取所有的RouteDefinition,这个在上面已经分析过了,接下来分析下convertToRoute是如何将RouteDefinition转换为Route实例的:

scss 复制代码
private Route convertToRoute(RouteDefinition routeDefinition) {
	AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
	List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
	//使用构造器AsyncBuilder构造Route实例
	return Route.async(routeDefinition).asyncPredicate(predicate)
			.replaceFilters(gatewayFilters).build();
}

public static AsyncBuilder async(RouteDefinition routeDefinition) {	
	return new AsyncBuilder().id(routeDefinition.getId())
			.uri(routeDefinition.getUri())
			.order(routeDefinition.getOrder())
			.metadata(routeDefinition.getMetadata());	
}

public Route build() {
	return new Route(this.id, this.uri, this.order, predicate, this.gatewayFilters, this.metadata);
}

这里使用了构造器AsyncBuilder来构造Route实例,Route.async首先从routeDefinition读取信息到构造器,然后设置构造器的Predicate和Filter,最后构造Route实例。

六、根据Http请求匹配Route:

1、流程:

SpringCloud Gateway依赖于框架Spring WebFlux,因此他的总入口不是DispatcherServlet而是DispatcherHandler,入口方法在handle中:

scss 复制代码
public Mono<Void> handle(ServerWebExchange exchange) {	
	return Flux.fromIterable(this.handlerMappings)
			//匹配到Route
			.concatMap(mapping -> mapping.getHandler(exchange))
			.next()
			.switchIfEmpty(createNotFoundError())
			//通过FilteringWebHandler执行过滤器链和执行业务代码
			.flatMap(handler -> invokeHandler(exchange, handler))
			//处理返回结果数据
			.flatMap(result -> handleResult(exchange, result));
}

a、首先使用HandlerMapping从http请求匹配到Route,并返回FilteringWebHandler对象(mapping.getHandler(exchange));

b、接着通过FilteringWebHandler执行过滤器链和执行业务代码(invokeHandler(exchange, handler));

c、处理返回结果数据(handleResult(exchange, result));

2、HandlerMapping的初始化:

在DispatcherHandler的构造方法中从Spring容器过滤出所有实现了HandlerMapping接口的bean。

ini 复制代码
public class DispatcherHandler implements WebHandler, ApplicationContextAware {

	private List<HandlerMapping> handlerMappings;

	private List<HandlerAdapter> handlerAdapters;

	private List<HandlerResultHandler> resultHandlers;
	
	public DispatcherHandler(ApplicationContext applicationContext) {
		initStrategies(applicationContext);
	}
	
	protected void initStrategies(ApplicationContext context) {
		Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
		this.handlerMappings = Collections.unmodifiableList(mappings);

		Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
		this.handlerAdapters = new ArrayList<>(adapterBeans.values());	

		Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerResultHandler.class, true, false);
		this.resultHandlers = new ArrayList<>(beans.values());		
	}	
	................
}

3、HandlerMapping匹配Route

HandlerMapping接口用于从http请求信息匹配到对应的Route,这个接只定义了一个方法getHandler,代码如下:

csharp 复制代码
public interface HandlerMapping {
	Mono<Object> getHandler(ServerWebExchange exchange);
}

HandlerMapping接口的实现类有很多,我们这里就分析下RoutePredicateHandlerMapping实现类是怎么匹配的流程:

scss 复制代码
public Mono<Object> getHandler(ServerWebExchange exchange) {
	return getHandlerInternal(exchange).map(handler -> {		
		return handler;
	});
}

protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {	
	//lookupRoute依据exchange匹配Route
	return lookupRoute(exchange)			
			.flatMap((Function<Route, Mono<?>>) r -> {				
				exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
				//返回FilteringWebHandler对象
				return Mono.just(webHandler);
			});
}

protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
	//routeLocator.getRoutes()返回所有的Route实例
	return this.routeLocator.getRoutes()			
			.concatMap(route -> Mono.just(route).filterWhen(r -> {				
				exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
				//过滤出断言为true的route
				return r.getPredicate().apply(exchange);
			}));	
}

this.routeLocator.getRoutes返回所有的Route实例,这在上面已经分析过了。接下来遍历所有的Route,r.getPredicate().apply(exchange)对Route的断言进行判断,过滤出返回true的Route,至此匹配Route路由就完成。

getHandlerInternal最后返回的webHandler对象,从定义可以看到这个 webHandler是FilteringWebHandler类型的,也就是后面将交由他来执行过滤器链。

七、执行过滤器链和业务代码:

1、适配器HandlerAdapter:

由于HandlerMapping不止RoutePredicateHandlerMapping一种实现,还有其他实现,在RoutePredicateHandlerMapping实现中返回的是FilteringWebHandler(带过滤器链的webHandler),而其他类型中有的是返回WebSocketHandler,有的返回的是HandlerMethod(不带过滤器链的,直接执行业务代码)等等,要以一种统一的方式调用的话,就需要封装一个适配器接口HandlerAdapter:

java 复制代码
public interface HandlerAdapter {
	boolean supports(Object handler);
	
	Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler);
}

supports用于判断持哪种类型的Handler,handle方法用于具体handler的调用。

执行业务代码的invokeHandler就是遍历所有的适配器HandlerAdapter,判断哪种适配器支持WebHandler则进行调用:

kotlin 复制代码
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
	if (this.handlerAdapters != null) {
		for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
			if (handlerAdapter.supports(handler)) {
				return handlerAdapter.handle(exchange, handler);
			}
		}
	}
	return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

支持WebHandler的适配器是SimpleHandlerAdapter:

typescript 复制代码
public class SimpleHandlerAdapter implements HandlerAdapter {
	@Override
	public boolean supports(Object handler) {
		return WebHandler.class.isAssignableFrom(handler.getClass());
	}

	@Override
	public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
		WebHandler webHandler = (WebHandler) handler;
		//这里会进入FilteringWebHandler.handle的调用
		Mono<Void> mono = webHandler.handle(exchange);
		return mono.then(Mono.empty());
	}
}

2、FilteringWebHandler的调用:

FilteringWebHandler首先加载全局过滤器:

java 复制代码
public class FilteringWebHandler implements WebHandler {

	private final List<GatewayFilter> globalFilters;

	public FilteringWebHandler(List<GlobalFilter> globalFilters) {
		this.globalFilters = loadFilters(globalFilters);
	}

	private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
		return filters.stream().map(filter -> {
			//利用适配器将GlobalFilter和GatewayFilter放到一个列表中
			GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);			
			return gatewayFilter;
		}).collect(Collectors.toList());
	}
	..............
}

private static class GatewayFilterAdapter implements GatewayFilter {
	private final GlobalFilter delegate;

	GatewayFilterAdapter(GlobalFilter delegate) {
		this.delegate = delegate;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		return this.delegate.filter(exchange, chain);
	}
}

全局过滤器GlobalFilter和Route过滤器GatewayFilter不是一个接口,不能放到一个集合中进行统一调用,因此定义了一个适配器GatewayFilterAdapter继承自GatewayFilter,这样两种过滤器就可以放到一个集合中统一调用了。

FilteringWebHandler的调用:

ini 复制代码
public Mono<Void> handle(ServerWebExchange exchange) {
	Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
	List<GatewayFilter> gatewayFilters = route.getFilters();

	//合并全局过滤器和Route过滤器
	List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
	combined.addAll(gatewayFilters);	

	//交由DefaultGatewayFilterChain执行
	return new DefaultGatewayFilterChain(combined).filter(exchange);
}

首先将全局过滤器和Route过滤器合并到一个集合,然后交由DefaultGatewayFilterChain执行:

kotlin 复制代码
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
	//当前执行的过滤器的游标
	private final int index;
	//过滤器集合
	private final List<GatewayFilter> filters;

	DefaultGatewayFilterChain(List<GatewayFilter> filters) {
		this.filters = filters;
		this.index = 0;
	}

	private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
		this.filters = parent.getFilters();
		this.index = index;
	}

	public List<GatewayFilter> getFilters() {
		return filters;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange) {
		return Mono.defer(() -> {
			if (this.index < filters.size()) {
				GatewayFilter filter = filters.get(this.index);
				DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
				//执行过滤器代码
				return filter.filter(exchange, chain);
			}
			else {
				return Mono.empty(); // complete
			}
		});
	}
}

DefaultGatewayFilterChain是一个过滤器链,里面保存了一个过滤器集合和当前执行的游标,每次执行filter时,根据index取出过滤器执行,然后游标加一,将加一后的游标重新构造DefaultGatewayFilterChain去执行,直至所有的过滤器执行完成,最后返回Mono.empty()表示完成。

不对,所有过滤器执行完后不是应该再去执行业务代码吗,怎么返回Mono.empty()了,这样业务代码是不是就没地方执行了。断点调试看看过滤器链的数据,其中有过滤器NettyRoutingFilter和NettyWriteResponseFilter,NettyRoutingFilter负责发送请求到route目标地址服务执行,NettyWriteResponseFilter则负责将目标服务执行的结果输出到客户端。下面分别看看这两个过滤器。

3、请求业务代码和将执行结果写回客户端:

先看看NettyRoutingFilter的代码:

java 复制代码
public class NettyRoutingFilter implements GlobalFilter, Ordered {
	private final HttpClient httpClient;	

	private final HttpClientProperties properties;
	
	@Override
	public int getOrder() {
		//排序在过滤器链集合最后
		return Ordered.LOWEST_PRECEDENCE;
	}

	@Override	
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

		String scheme = requestUrl.getScheme();
		if (isAlreadyRouted(exchange) || (!"http".equals(scheme) && !"https".equals(scheme))) {
			return chain.filter(exchange);
		}
		setAlreadyRouted(exchange);
		
		........省略部分代码..........

		ServerHttpRequest request = exchange.getRequest();
		final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
		final String url = requestUrl.toASCIIString();		
		Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);

		//getHttpClient返回的就是httpClient,这里将请求发送给后端微服务执行
		Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)
				.request(method).uri(url).send((req, nettyOutbound) -> {					
					return nettyOutbound.send(request.getBody().map(this::getByteBuf));
				});	
		//交给过滤器链的下一个过滤器执行
		return responseFlux.then(chain.filter(exchange));
	}
}

getOrder方法可以看到这个过滤器是排在过滤器链的最后面。filter方法首先获取业务服务真正的请求requestUrl,再用getHttpClient(route, exchange)获取到httpClient对象,接着调用httpClient向业务服务发送请求,将返回结果交由过滤器链的下一个过滤器来执行。

再看看NettyWriteResponseFilter的代码:

java 复制代码
public class NettyWriteResponseFilter implements GlobalFilter, Ordered {	
	@Override
	public int getOrder() {
		//在过滤器链中的位置还是比较靠前的
		return -1;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {	
		//chain.filter(exchange).then表示先交由过滤器链执行后面的过滤器,等后面的执行完成后再执行then后面的代码,相当于After Filter的效果
		return chain.filter(exchange)				
				.then(Mono.defer(() -> {
					//获取Connection
					Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR);
					if (connection == null) {
						return Mono.empty();
					}
					
					//获取ServerHttpResponse
					ServerHttpResponse response = exchange.getResponse();
					//获取数据并转换数据
					final Flux<DataBuffer> body = connection
							.inbound()
							.receive()
							.retain()
							.map(byteBuf -> wrap(byteBuf, response));

					MediaType contentType = response.getHeaders().getContentType();	
					//writeAndFlushWith或writeWith都是将返回数据写回客户端
					return (isStreamingMediaType(contentType)
							? response.writeAndFlushWith(body.map(Flux::just))
							: response.writeWith(body));
				}));	
	}
}

getOrder的代码可以看到这个过滤器在过滤器链比较靠前的位置。filter方法,chain.filter(exchange).then表示先交由过滤器链执行后面的过滤器,等后面的执行完成后再执行then后面的代码,相当于After Filter的效果。then后面的代码首先获取Connection和ServerHttpResponse,接着获取返回业务请求返回数据并转换后的body,最后通过/writeAndFlushWith或writeWith都是将返回数据写回客户端。

相关推荐
代码驿站5206 分钟前
Lua语言的函数实现
开发语言·后端·golang
李歘歘13 分钟前
Golang笔记——切片与数组
开发语言·笔记·后端·golang·go
诸神缄默不语16 分钟前
Java SE 与 Java EE 简介
java·数据库·java-ee·java se
Yicsr23 分钟前
在Visual Studio中编译.c文件和.cpp文件主要有哪些不同
java·c语言·visual studio
开心呆哥31 分钟前
【python翻译软件V1.0】
java·服务器·python
raoxiaoya40 分钟前
golang中的eval,goeval,govaluate
开发语言·后端·golang
CyberScriptor1 小时前
PHP语言的软件工程
开发语言·后端·golang
TANGLONG2221 小时前
【C++】揭开C++类与对象的神秘面纱(首卷)(类的基础操作详解、实例化艺术及this指针的深究)
java·开发语言·数据结构·c++·python·考研·面试
GGBondlctrl1 小时前
【SpringAOP】Spring AOP 底层逻辑:切点表达式与原理简明阐述
java·后端·代理模式·spring aop·切点表达式
代码驿站5201 小时前
Scala语言的软件开发工具
开发语言·后端·golang