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分发处理
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与原理是一致的)
- 通过过滤器来处理请求到具体业务服务
004-spring cloud gateway-网关请求处理过程的更多相关文章
- .net core下,Ocelot网关与Spring Cloud Gateway网关的对比测试
有感于 myzony 发布的 针对 Ocelot 网关的性能测试 ,并且公司下一步也需要对.net和java的应用做一定的整合,于是对Ocelot网关.Spring Cloud Gateway网关做个 ...
- Spring Cloud gateway 网关服务二 断言、过滤器
微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...
- Spring Cloud gateway 网关四 动态路由
微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...
- Spring Cloud实战 | 第十一篇:Spring Cloud Gateway 网关实现对RESTful接口权限控制和按钮权限控制
一. 前言 hi,大家好,这应该是农历年前的关于开源项目 的最后一篇文章了. 有来商城 是基于 Spring Cloud OAuth2 + Spring Cloud Gateway + JWT实现的统 ...
- 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析
API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...
- Spring Cloud gateway 网关服务 一
之前我们介绍了 zuul网关服务,今天聊聊spring cloud gateway 作为spring cloud的亲儿子网关服务.很多的想法都是参照zuul,为了考虑zuul 迁移到gateway 提 ...
- 微服务架构spring cloud - gateway网关限流
1.算法 在高并发的应用中,限流是一个绕不开的话题.限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击. 一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池.线程池). ...
- Spring Cloud Gateway 网关限流
Spring Cloud Gateway 限流 一.背景 二.实现功能 三.网关层限流 1.使用默认的redis来限流 1.引入jar包 2.编写配置文件 3.网关正常响应 4.网关限流响应 2.自定 ...
- 从零搭建Spring Cloud Gateway网关(一)
新建Spring Boot项目 怎么新建Spring Boot项目这里不再具体赘述,不会的可以翻看下之前的博客或者直接百度.这里直接贴出对应的pom文件. pom依赖如下: <?xml vers ...
- 从零搭建Spring Cloud Gateway网关(二)—— 打印请求响应日志
作为网关,日志记录是必不可少的功能,可以在网关出增加requestId来查询整个请求链的调用执行情况等等. 打印请求日志 打印请求日志最重要的就是打印请求参数这些东西,不过RequestBody通常情 ...
随机推荐
- windows下使用git管理代码,其中出现的问题的解决办法
和朋友共同开发一个小项目,所以就涉及到了代码管理这块,刚开始想到的是使用svn,但是外网访问svn的时候需要使用花生壳来弄一个动态的域名,中间出了很多错误,感觉有点麻烦,所以就想到看看还有别的管理代码 ...
- spring基础---->请求与响应的参数(一)
这里面我们主要介绍一下spring中关于请求和响应参数数据的问题.爱,从来就是一件千回百转的事.不曾被离弃,不曾受伤害,怎懂得爱人?爱,原来是一种经历. spring中的请求与响应 一.spring中 ...
- vue笔记 - 生命周期第二次学习与理解
对于刚接触vue一两个月.才仅仅独立做过一两个vue项目的小白来说,以前一直自我感觉自己知道vue的生命周期, 直到前两天去面试,面试官让我说一下vue的生命周期... 其实我的心中是有那张图的,但是 ...
- 二分法求平方根(Python实现)
使用二分法(Bisection Method)求平方根. def sqrtBI(x, epsilon): assert x>0, 'X must be non-nagtive, not ' + ...
- nginx fastcgi配置
1.1 nginx概述nginx简介Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为“engine X”, 是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/P ...
- 【转】Navigation Drawer(导航抽屉)
创建一个导航抽屉 创建抽屉布局 初始化抽屉列表 处理导航项选点击事件 监听导航抽屉打开和关闭事件 点击应用图标来打开和关闭导航抽屉 创建一个导航抽屉 导航抽屉是一个位于屏幕左侧边缘用来显示应用程序 ...
- VS2003安装Opencv1.0 windows系统 win7
一.步骤 下载安装opencv1.0 安装文件我上传到百度网盘分享连接 http://pan.baidu.com/s/1o8na0aA 配置电脑windows环境变量 配置VS2003全局设置 ...
- Apache服务器301重定向去掉.html和.php
在做优化网站的时候,会考虑到网站整站的集权: 考虑到网站可以生成静态,首先,让网站优先访问 index.html 之后考虑:去掉 .html 和 .php. 利用 .htaccess <IfMo ...
- &与&&, |与||区别
&和|称为短逻辑符,&&及||称为长逻辑符.长逻辑符只比较左边和右边的第一个元素,而短逻辑符会比较所有的 > a<-c(TRUE, FALSE, TRUE, FAL ...
- Centos7搭建vsftp服务器
环境查看 安装vsftp软件 yum -y install vsftpd 修改配置文件/etc/vsftpd/vsftpd.conf (其余配置保持默认即可) anonymous_enable=NO ...