目录
一、概述
二、过滤器
二、网关过滤器 GatewayFilter
1. Path 路径过滤器
2. Parameter 参数过滤器
3. Status 状态过滤器
三、全局过滤器 GlobalFilter
1. 自定义过滤器
2. 自定义网关过滤器
3. 统一鉴权
Spring Cloud Gateway 学习专栏
1. Spring Cloud : Gateway 服务网关认识(一)
2. Spring Cloud :整合Gateway 学习 (二)
3. Spring Cloud:Gateway 路由定义定位器 RouteDefinitionLocator (三)
4. Spring Cloud : Gateway 网关过滤器 GatewayFilter(四)
5. Spring Cloud : Gateway 网关限流(五)
6. Spring Cloud:Gateway 集成 Sentinel (六)
7. Spring Cloud : Gateway Redis动态路由 (七)
8. Spring Cloud : Gateway 整合Swagger (八)
?
?
如果发现本文有错误的地方,请大家毫不吝啬,多多指教,欢迎大家评论,谢谢!
一、概述
本篇文章为系列文章,未读第 上一集 的同学请猛戳这里: Spring Cloud :整合Gateway 学习 (二),下面是讲解网关过滤器 GatewayFilter 使用
二、过滤器Spring Cloud Gateway 根据作用范围划分为 GatewayFilter 和 GlobalFilter,二者区别如下:
GatewayFilter:网关过滤器,需要通过 spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过 spring.cloud.default-filters 配置在全局,作用在所有路由上。GlobalFilter:全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过 GatewayFilterAdapter 包装成 GatewayFilterChain 可识别的过滤器,它为请求业务以及路由的 URI 转换为真实业务服务请求地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上。二、网关过滤器 GatewayFilter
?????? 网关过滤器用于拦截并链式处理 Web 请求,可以实现横切与应用无关的需求,比如:安全、访问超时的设置等。修改传入的 HTTP 请求或传出 HTTP 响应。Spring Cloud Gateway 包含许多内置的网关过滤器工厂一共有 22 个,包括头部过滤器、 路径类过滤器、Hystrix 过滤器和重写请求 URL 的过滤器, 还有参数和状态码等其他类型的过滤器。根据过滤器工厂的用途来划分,可以分为以下几种:Header、Parameter、Path、Body、Status、Session、Redirect、Retry、RateLimiter 和 Hystrix。
?
?
接下来我们举例说明其中一部分如何使用,其余等大家工作中需要应用时再查询资料学习或者咨询我也可以。
1. Path 路径过滤器
Path 路径过滤器可以实现 URL 重写,通过重写 URL 可以实现隐藏实际路径提高安全性,易于用户记忆和键入,易于被搜索引擎收录等优点。实现方式如下:
RewritePathGatewayFilterFactory
RewritePath 网关过滤器工厂采用路径正则表达式参数和替换参数,使用 Java 正则表达式来灵活地重写请求路径。
server: port: 9000 service-url: user-service: http://localhost:8200 spring: application: name: mall-gateway main: allow-bean-definition-overriding: true ## redis配置 redis: database: 0 host: 47.103.20.21 password: zlp123456 port: 6379 timeout: 7000 cloud: ## nacos注册中心 nacos: discovery: server-addr: 47.103.20.21:8848 ## gateway配置 gateway: routes: - id: user #路由的ID 保证唯一 uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称 predicates: # 断言,路径相匹配的进行路由 (谓词) - Path=/user/** # 路径匹配 filters: #将 /user/user/getUserInfo?userId=1 重写为 /user/getUserInfo?userId=1 - RewritePath=/user/(?<segment>.*),/$\{segment}访问:http://127.0.0.1:9000/user/user/getUserInfo?userId=1 结果如下:
?
PrefixPathGatewayFilterFactory
PrefixPath 网关过滤器工厂为匹配的 URI 添加指定前缀
server: port: 9000 service-url: user-service: http://localhost:8200 spring: application: name: mall-gateway main: allow-bean-definition-overriding: true ## redis配置 redis: database: 0 host: 47.103.20.21 password: zlp123456 port: 6379 timeout: 7000 cloud: ## nacos注册中心 nacos: discovery: server-addr: 47.103.20.21:8848 ## gateway配置 gateway: routes: - id: user #路由的ID 保证唯一 uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称 predicates: # 断言,路径相匹配的进行路由 (谓词) - Path=/** # 所有路径都匹配 filters: # 将 /user/getUserInfo?userId=1 重写为 /user/user/getUserInfo?userId=1 - PrefixPath=/user?
访问:http://127.0.0.1:9000/user/getUserInfo?userId=1 结果如下:
?
StripPrefixGatewayFilterFactory
StripPrefix 网关过滤器工厂采用一个参数 StripPrefix,该参数表示在将请求发送到下游之前从请求中剥离的路径个数。
server: port: 9000 service-url: user-service: http://localhost:8200 spring: application: name: mall-gateway main: allow-bean-definition-overriding: true ## redis配置 redis: database: 0 host: 47.103.20.21 password: zlp123456 port: 6379 timeout: 7000 cloud: ## nacos注册中心 nacos: discovery: server-addr: 47.103.20.21:8848 ## gateway配置 gateway: routes: - id: user #路由的ID 保证唯一 uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称 predicates: # 断言,路径相匹配的进行路由 (谓词) - Path=/** # 所有路径都匹配 filters: # 将 /api/user/getUserInfo?userId=1 重写为 user/getUserInfo?userId=1 - StripPrefix=1访问:http://127.0.0.1:9000/api/user/getUserInfo?userId=1 结果如下:
?
?
SetPathGatewayFilterFactory
SetPath 网关过滤器工厂采用路径模板参数。 它提供了一种通过允许模板化路径段来操作请求路径的简单方法,使用了 Spring Framework 中的 uri 模板,允许多个匹配段。
server: port: 9000 service-url: user-service: http://localhost:8200 spring: application: name: mall-gateway main: allow-bean-definition-overriding: true ## redis配置 redis: database: 0 host: 47.103.20.21 password: zlp123456 port: 6379 timeout: 7000 cloud: ## nacos注册中心 nacos: discovery: server-addr: 47.103.20.21:8848 ## gateway配置 gateway: routes: - id: user #路由的ID 保证唯一 uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称 predicates: # 匹配对应 URI 的请求,将匹配到的请求追加在目标 URI 之后 - Path=/api/user/{segment} filters: # 将 /api/user/getUserInfo?userId=1 重写为 /user/getUserInfo?userId=1 - SetPath=/user/{segment}访问:http://127.0.0.1:9000/api/user/getUserInfo?userId=1 结果如下:
?
?
2. Parameter 参数过滤器AddRequestParameter
网关过滤器工厂会将指定参数添加至匹配到的下游请求中。
server: port: 9000 service-url: user-service: http://localhost:8200 spring: application: name: mall-gateway main: allow-bean-definition-overriding: true ## redis配置 redis: database: 0 host: 47.103.20.21 password: zlp123456 port: 6379 timeout: 7000 cloud: ## nacos注册中心 nacos: discovery: server-addr: 47.103.20.21:8848 ## gateway配置 gateway: routes: - id: user #路由的ID 保证唯一 uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称 predicates: # 匹配对应 URI 的请求,将匹配到的请求追加在目标 URI 之后 - Path=/api/user/{segment} filters: # 将 /user/user/getUserInfo?userId=1 重写为 /user/getUserInfo?userId=1 - RewritePath=/user/(?<segment>/?.*), $\{segment} # 在下游请求中添加 flag=1 - AddRequestParameter=flag, 1修改用户服务的控制层代码
添加一个 getUserParam 获取网关请求自定义参数接口
@GetMapping("getUserParam") @ApiOperation(value = "获取用户参数信息") public UserResp getUserParam(HttpServletRequest request, @RequestParam("userId") @ApiParam(name = "userId",value = "用户ID") Long userId ) { String foo = request.getParameter("foo"); log.info("getUserHead.resp foo={}",foo); UserResp userResp = UserResp.builder() .id(userId) .createTime(new Date()) .nickname("change") .username("Zou.LiPing") .roleName("超级管理员") .build(); return userResp; }访问:http://127.0.0.1:9000/user/user/getUserParam?userId=1 控制台结果如下:
UserController : getUserHead.resp foo=bar 3. Status 状态过滤器
SetStatus 网关过滤器工厂采用单个状态参数,它必须是有效的 Spring HttpStatus。它可以是整数 404 或枚举 NOT_FOUND 的字符串表示。
server: port: 9000 service-url: user-service: http://localhost:8200 spring: application: name: mall-gateway main: allow-bean-definition-overriding: true ## redis配置 redis: database: 0 host: 47.103.20.21 password: zlp123456 port: 6379 timeout: 7000 cloud: ## nacos注册中心 nacos: discovery: server-addr: 47.103.20.21:8848 ## gateway配置 gateway: routes: - id: user #路由的ID 保证唯一 uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称 predicates: # 匹配对应 URI 的请求,将匹配到的请求追加在目标 URI 之后 - Path=/api/user/{segment} filters: # 将 /user/user/getUserInfo?userId=1 重写为 /user/getUserInfo?userId=1 - RewritePath=/user/(?<segment>/?.*), $\{segment} # 任何情况下,响应的 HTTP 状态都将设置为 404 - SetStatus=404 # 404 或者对应的枚举 NOT_FOUND访问:http://127.0.0.1:9000/user/user/getUserParam?userId=1 控制台结果如下:
?
三、全局过滤器 GlobalFilter
全局过滤器不需要在配置文件中配置,作用在所有的路由上,最终通过 GatewayFilterAdapter 包装成 GatewayFilterChain 可识别的过滤器,它是请求业务以及路由的 URI 转换为真实业务服务请求地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上。
?
1. 自定义过滤器即使 Spring Cloud Gateway 自带许多实用的 GatewayFilter Factory、Gateway Filter、Global Filter,但是在很多情景下我们仍然希望可以自定义自己的过滤器,实现一些骚操作。
2. 自定义网关过滤器自定义网关过滤器需要实现以下两个接口 :GatewayFilter,Ordered。
创建过滤器
?CustomGatewayFilter.java
@Slf4j @Component public class CustomGatewayFilter implements GatewayFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("自定义网关过滤器..."); return chain.filter(exchange);// 继续向下执行 } @Override public int getOrder() { return 0; } }注册过滤器?
package com.example.config; import com.example.filter.CustomGatewayFilter; 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 public class GatewayRoutesConfiguration { @Bean public RouteLocator routeLocator(RouteLocatorBuilder builder) { return builder.routes().route(r -> r // 断言(判断条件) .path("/product/**") // 目标 URI,路由到微服务的地址 .uri("lb://ai-product") // 注册自定义网关过滤器 .filters(new CustomGatewayFilter()) // 路由 ID,唯一 .id("product")) .build(); } }访问
注释配置文件中所有网关配置,重启并访问:http://localhost:9000/product/getProduct?productId=1 控制台结果如下:
自定义网关过滤器被执行 3. 统一鉴权接下来我们在网关过滤器中通过 token 判断用户是否登录,完成一个统一鉴权案例。
AuthorizeFilter
/** * 认证过滤器 * @date: 2021/4/22 19:30 */ @Component public class AuthorizeFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest serverHttpRequest = exchange.getRequest(); ServerHttpResponse serverHttpResponse = exchange.getResponse(); // 获取 token 参数 String token = serverHttpRequest.getHeaders().getFirst("token"); if (StringUtils.isBlank(token)) { serverHttpResponse.setStatusCode(HttpStatus.UNAUTHORIZED); return getVoidMono(serverHttpResponse, ResultCode.TOKEN_MISSION); } return chain.filter(exchange); } @Override public int getOrder() { return 1; } /** * 错误信息响应到客户端 * @param serverHttpResponse Response * @param resultCode 错误枚举 * @date: 2021/4/20 9:13 * @return: reactor.core.publisher.Mono<java.lang.Void> */ private Mono<Void> getVoidMono(ServerHttpResponse serverHttpResponse, ResultCode resultCode) { serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); DataBuffer dataBuffer = serverHttpResponse.bufferFactory().wrap(JSON.toJSONString(Result.failed(resultCode)).getBytes()); return serverHttpResponse.writeWith(Flux.just(dataBuffer)); } }访问
重启并访问:http://localhost:9000/product/getProduct?productId=1
我在头部请求 token 参数
源码地址
mall-gateway 这个项目
https://gitee.com/gaibianzlp/zlp-mall-demo.git
?
参考链接1. Spring Cloud 系列之 Gateway 服务网关
?
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。 |
标签: #Spring #Cloud #gateway #网关过滤器 #GatewayFilter四