zoukankan      html  css  js  c++  java
  • 004-spring cloud gateway-网关请求处理过程

    一、网关请求处理过程

       

      客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。此处理程序运行通过特定于请求的过滤器链发送请求。滤波器被虚线划分的原因是滤波器可以在发送代理请求之前或之后执行逻辑。执行所有“pre”过滤器逻辑,然后进行代理请求。在发出代理请求之后,执行“post”过滤器逻辑。

       在没有端口的路由中定义的URI将分别为HTTP和HTTPS URI获取默认端口设置为80和443。

    • DispatcherHandler:所有请求的调度器,负载请求分发
    • RoutePredicateHandlerMapping:路由谓语匹配器,用于路由的查找,以及找到路由后返回对应的WebHandler,DispatcherHandler会依次遍历HandlerMapping集合进行处理
    • FilteringWebHandler : 使用Filter链表处理请求的WebHandler,RoutePredicateHandlerMapping找到路由后返回对应的FilteringWebHandler对请求进行处理,FilteringWebHandler负责组装Filter链表并调用链表处理请求。

    1.1、DispatcherHandler分发处理

    在import org.springframework.web.reactive.DispatcherHandler;类中核心方法handle
        public Mono<Void> handle(ServerWebExchange exchange) {
            if (logger.isDebugEnabled()) {
                ServerHttpRequest request = exchange.getRequest();
                logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
            }
            //校验handlerMapping集合是否为空
            //依次遍历handlerMapping集合进行请求处理
            //通过mapping获取mapping对应的handler,调用handler处理
            return this.handlerMappings == null ? Mono.error(HANDLER_NOT_FOUND_EXCEPTION) : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
                return mapping.getHandler(exchange);
            }).next().switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION)).flatMap((handler) -> {
                return this.invokeHandler(exchange, handler);
            }).flatMap((result) -> {
                return this.handleResult(exchange, result);
            });
        }        

    DispatcherHandler的handler执行顺序

    • 校验handlerMapping
    • 遍历Mapping获取mapping对应的handler(此处会找到gateway对应的 RoutePredicateHandlerMapping,并通过 RoutePredicateHandlerMapping获取handler(FilteringWebHandler))
    • 通过handler对应的HandlerAdapter对handler进行调用(gateway使用的 SimpleHandlerAdapter) 即 FilteringWebHandler与SimpleHandlerAdapter对应
      

    其中SimpleHandlerAdapter中handler实现

        public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
            WebHandler webHandler = (WebHandler)handler;
            Mono<Void> mono = webHandler.handle(exchange);
            return mono.then(Mono.empty());
        }

    1.2、RoutePredicateHandlerMapping 路由谓词处理映射

    public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
        private final FilteringWebHandler webHandler;
        private final RouteLocator routeLocator;
    
        public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties) {
            this.webHandler = webHandler;
            this.routeLocator = routeLocator;
            //设置排序字段1,此处的目的是Spring Cloud Gateway 的 GatewayWebfluxEndpoint 提供 HTTP API ,不需要经过网关
            //它通过 RequestMappingHandlerMapping 进行请求匹配处理。RequestMappingHandlerMapping 的 order = 0 ,
            // 需要排在 RoutePredicateHandlerMapping 前面。所有,RoutePredicateHandlerMapping 设置 order = 1 。
            this.setOrder(1);
            this.setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
        }
    
        protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
            //设置mapping到上下文环境
            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR, this.getClass().getSimpleName());
            // 查找路由
            return this.lookupRoute(exchange).flatMap((r) -> {
                exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Mapping [" + this.getExchangeDesc(exchange) + "] to " + r);
                }
                //将找到的路由信息设置到上下文环境中
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
                //返回mapping对应的WebHandler即FilteringWebHandler
                return Mono.just(this.webHandler);
            }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
                //当前未找到路由时返回空,并移除GATEWAY_PREDICATE_ROUTE_ATTR
                exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("No RouteDefinition found for [" + this.getExchangeDesc(exchange) + "]");
                }
    
            })));
        }
    
        protected CorsConfiguration getCorsConfiguration(Object handler, ServerWebExchange exchange) {
            return super.getCorsConfiguration(handler, exchange);
        }
    
        private String getExchangeDesc(ServerWebExchange exchange) {
            StringBuilder out = new StringBuilder();
            out.append("Exchange: ");
            out.append(exchange.getRequest().getMethod());
            out.append(" ");
            out.append(exchange.getRequest().getURI());
            return out.toString();
        }
    
        protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
            //通过路由定位器获取路由信息
            return this.routeLocator.getRoutes().concatMap((route) -> {
                return Mono.just(route).filterWhen((r) -> {
                    exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                    return (Publisher)r.getPredicate().apply(exchange);
                }).doOnError((e) -> {
                    this.logger.error("Error applying predicate for route: " + route.getId(), e);
                }).onErrorResume((e) -> {
                    return Mono.empty();
                });
            }).next().map((route) -> {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Route matched: " + route.getId());
                }
    
                this.validateRoute(route, exchange);
                return route;
            });
        }
    
        protected void validateRoute(Route route, ServerWebExchange exchange) {
        }
    }

    RoutePredicateHandlerMapping的执行顺序

    • 通过路由定位器获取全部路由(RouteLocator)
    • 通过路由的谓语(Predicate)过滤掉不可用的路由信息
    • 查找到路由信息后将路由信息设置当上下文环境中(GATEWAY_ROUTE_ATTR)
    • 返回gatway自定的webhandler(FilteringWebHandler)
    备注:
    在构建方法中看到setOrder(1);作用:Spring Cloud Gateway 的 GatewayWebfluxEndpoint 提供 HTTP API ,不需要经过网关。
    通过 RequestMappingHandlerMapping 进行请求匹配处理。RequestMappingHandlerMapping 的 order = 0 ,需要排在 RoutePredicateHandlerMapping 前面,所以设置 order = 1 。

    1.3、FilteringWebHandler 过滤web请求处理

    /**
     * 通过过滤器处理web请求的处理器
     */
    public class FilteringWebHandler implements WebHandler {
        protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class);
    
        /**
         * 全局过滤器
         */
        private final List<GatewayFilter> globalFilters;
    
        public FilteringWebHandler(List<GlobalFilter> globalFilters) {
            this.globalFilters = loadFilters(globalFilters);
        }
    
        /**
         * 包装加载全局的过滤器,将全局过滤器包装成GatewayFilter
         */
        private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
            return filters.stream()
                    .map(filter -> {
                        //将所有的全局过滤器包装成网关过滤器
                        GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
                        //判断全局过滤器是否实现了可排序接口
                        if (filter instanceof Ordered) {
                            int order = ((Ordered) filter).getOrder();
                            //包装成可排序的网关过滤器
                            return new OrderedGatewayFilter(gatewayFilter, order);
                        }
                        return gatewayFilter;
                    }).collect(Collectors.toList());
        }
    
        @Override
        public Mono<Void> handle(ServerWebExchange exchange) {
            //获取请求上下文设置的路由实例
            Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
            //获取路由定义下的网关过滤器集合
            List<GatewayFilter> gatewayFilters = route.getFilters();
            //组合全局的过滤器与路由配置的过滤器
            List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
            //添加路由配置过滤器到集合尾部
            combined.addAll(gatewayFilters);
            //对过滤器进行排序
            AnnotationAwareOrderComparator.sort(combined);
    
            logger.debug("Sorted gatewayFilterFactories: "+ combined);
            //创建过滤器链表对其进行链式调用
            return new DefaultGatewayFilterChain(combined).filter(exchange);
        }
    }

    FilteringWebHandler的执行顺序

    • 构建一个包含全局过滤器的集合(combined)
    • 获取上下中的路由信息GATEWAY_ROUTE_ATTR
    • 将路由里的过滤器添加到集合中(combined)
    • 对过滤器集合进行排序操作
    • 通过过滤器集合组装过滤器链表,并进行调用(DefaultGatewayFilterChain与Servlet中的FilterChain与原理是一致的)
    • 通过过滤器来处理请求到具体业务服务
  • 相关阅读:
    经典的Java基础面试题集锦
    2016春招Android开发实习生(网易传媒)笔试
    十三、集合点和事务
    十一、LoadRunner组成和工作原理
    Java+selenium之WebDriver常见特殊情况如iframe/弹窗处理(四)
    修改jar包内容并打包上传到私服
    Information:java: Multiple encodings set for module chunk platf "GBK" will be used by compile
    十、创建、运行和监控测试场景
    在gitlab新建分支,IDEA切换时找不到的解决办法
    Git 代码撤销、回滚到任意版本(当误提代码到本地或master分支时)
  • 原文地址:https://www.cnblogs.com/bjlhx/p/9588739.html
Copyright © 2011-2022 走看看