1、是什么

路由过滤器可用于修改进入HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用

SpringCloud GateWay 内置了多种路由过滤器,他们都由GateWayFilter的工厂类来产生

官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories

2、Spring Cloud GateWay的Filter

1、生命周期 Only Two

1、pre

2、post

2、种类 Only Two

1、GateWayFilter(网关过滤器)

2、GlobalFilter(全局过滤器)

3、常用的GateWayFilter

1、两个主要接口介绍

  1. public class MyLogGateWayFilter implements GlobalFilter, Ordered

2、能干嘛

全局日志记录
统一网关鉴定

4、自定义过滤器

  1. @Override
  2. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  3. log.info("*****************come in MyLogGateWayFilter"+new Date());
  4. String uname = exchange.getRequest().getQueryParams().getFirst("uname");
  5. if (uname==null){
  6. log.info("*******用户名为null, 非法用户 ,o(╥﹏╥)o");
  7. exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
  8. return exchange.getResponse().setComplete();
  9. }
  10. return chain.filter(exchange);
  11. }
  12. @Override
  13. public int getOrder() {
  14. return 0; //这个是优先级
  15. }

image.png
image.png

网关过滤器

Path路径过滤器

Path路径过滤器可以实现URL重写,通过重写URL可以实现隐藏实际路径提高安全性,易于用户记忆和键入,易于被搜索引擎收录等优点,实现方式如下:

1、RewritePathGateWayFilterFactory

ReWritePath网关过滤器工厂采用路径正则表达式参数和替换参数,使用Java正则表达式来灵活地重写请求路径

image.png

2、PrefixPathGateWayFilterFactory

PrefixPath网关过滤器工厂为匹配的URI添加指定前缀
image.png
请求image.png
发现可以正常请求,那是因为在filter添加了/product

3、StripPrefixGateWayFilterFactory

StripPrefix网关过滤器工厂采用了一个参数StripPrefix,该参数表示在将请求发送到下游之前从请求中剥离的路径个数。

image.png

4、SetpathGateWayFilterFactory

SetPath网关过滤器工厂采用路径模板参数,它提供了一种通过允许模板化路径段来操作请求路径的简单方法,使用了SpringFramework中的URI模板,允许多个匹配段
image.png

参数过滤器

AddRequestParameter网关过滤器工厂会将指定参数添加至匹配的下游请求中
image.png

Status状态过滤器

SetStatus网关过滤器工厂采用单个状态参数,它必须是有效的Spring HttpStatus,它可以是整数404 或枚举NoT_FOUND 的字符串表示
image.png
image.png
即使请求成功,也可以更改状态

全局过滤器

全局过滤器不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GateWayFilterChain可识别的过滤器,它是请求业务以及路由的URI转换为真实业务服务请求地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上。
image.png

自定义过滤器

自定义网关过滤器

自定义网关过滤器需要实现以下两个接口: GateWayFilter,Ordered。
(1)创建过滤器

  1. /**
  2. * 此过滤器功能为计算请求完成时间
  3. */
  4. public class MyFilter implements GatewayFilter, Ordered {
  5. private static final String ELAPSED_TIME_BEGIN = "elapsedTimeBegin";
  6. @Override
  7. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  8. exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
  9. return chain.filter(exchange).then(
  10. Mono.fromRunnable(() -> {
  11. Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
  12. if (startTime != null) {
  13. System.out.println(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
  14. }
  15. })
  16. );
  17. }
  18. /*
  19. *过滤器存在优先级,order越大,优先级越低
  20. */
  21. @Override
  22. public int getOrder() {
  23. return Ordered.LOWEST_PRECEDENCE;
  24. }
  25. }

(2)注册过滤器
定义好MyFilter以后其需要跟Route绑定使用,不能在application.yml文件中配置使用

  1. @Bean
  2. public RouteLocator routeLocator(RouteLocatorBuilder builder) {
  3. return builder.routes().route(r ->
  4. r.path("/abc/**")
  5. //去掉前缀1节
  6. .filters(p->p.stripPrefix(1))
  7. //转发路由
  8. .uri("lb://eureka-client")
  9. //注册自定义过滤器
  10. .filters(new MyFilter())
  11. //给定id
  12. .id("user-service")
  13. ).build();
  14. }

自定义全局过滤器

会在所有的路由上

自定义过滤器, 假设对请求头的token进行认证。

  1. /**
  2. * @Author: zhihao
  3. * @Date: 2020/3/31 17:38
  4. * @Description: 自定义过滤器
  5. * @Versions 1.0
  6. **/
  7. @Component //交给框架管理
  8. public class MyGatewayFilter implements GlobalFilter, Ordered {
  9. @Override
  10. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  11. //1.获取请求对象
  12. ServerHttpRequest request = exchange.getRequest();
  13. //2.获取请求头Authenticate
  14. List<String> authenticate = request.getHeaders().get("Authenticate");
  15. if (null == authenticate || authenticate.isEmpty()) {
  16. //说明Authenticate为空,返回错误码,阻止通过网关路由
  17. ServerHttpResponse response = exchange.getResponse();
  18. Map<String,String> resultMap = new LinkedHashMap<>();
  19. resultMap.put("code", "401");
  20. resultMap.put("message", "没有token");
  21. String jsonStr = JSONUtil.toJsonStr(resultMap);
  22. //将错误信息输出页面
  23. DataBuffer dataBuffer = response.bufferFactory().wrap(jsonStr.getBytes());
  24. response.setStatusCode(HttpStatus.UNAUTHORIZED); //状态码
  25. response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
  26. Mono<Void> mono = response.writeWith(Mono.just(dataBuffer));
  27. return mono;
  28. //return response.setComplete();
  29. }
  30. //......可以通过
  31. String[] strings = authenticate.toArray(new String[authenticate.size()]);
  32. String str = strings[0];
  33. return chain.filter(exchange);
  34. }
  35. @Override
  36. public int getOrder() {
  37. //值越大则优先级越低。
  38. return -1;
  39. }
  40. }

使用全局过滤器实现鉴权

image.png