03-详解网关的过滤器工厂和常见的网关过滤器路由过滤器,默认过滤器,全局过滤器的执行顺序

过滤器工厂

过滤器种类

GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务响应的结果做加工处理

Spring提供了31中不同的路由过滤器工厂

AddResponseHeader表示给请求添加响应头

yaml 复制代码
default-filters: # 默认过滤器
- AddResponseHeader=X-Response-Default-Red, Default-Blue # 添加响应头X-Response-Default-Red: Default-Blue

PrefixPath表示给请求添加路径前缀

yaml 复制代码
default-filters: # 默认过滤器
- PrefixPath=/httpbin

AddRequestHeader表示给请求添加key为X-Request-red,value为blue的请求头,可以应用于流量染色

yaml 复制代码
filters: # 服务过滤器
- AddRequestHeader=X-Request-red, blue # 添加请求头X-Request-red: blue

AddRequestHeadersIfNotPresent表示给请求添加请求头,但只有当请求头里没有对应的请求头时才会添加,如果有则会传递原始的请求头

yaml 复制代码
filters:
  # 添加多个请求头X-Request-Color-1:blue,X-Request-Color-2:green
- AddRequestHeadersIfNotPresent=X-Request-Color-1:blue,X-Request-Color-2:green 

AddRequestParameter表示给请求添加请求参数

yaml 复制代码
filters:
- AddRequestParameter=red, blue # 添加请求参数red=blue

AddResponseHeader表示给请求添加响应头

yaml 复制代码
filters:
- AddResponseHeader=X-Response-Red, Blue # 给请求添加响应头X-Response-Red: Blue

CircuitBreaker(断路器)用于给接口做降级,当接口报错时降级去请求另一个接口

  • 在使用断路器之前,需要先引入spring-cloud-starter-circuitbreaker-reactor-resilience4j依赖
yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingServiceEndpoint
        filters:
        - name: CircuitBreaker
          args:
            name: myCircuitBreaker
            fallbackUri: forward:/inCaseOfFailureUseThis
        - RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint

RequestRateLimiter表示使用Redis做限流,使用的令牌桶算法如漏桶算法RedisLimitHandler

yaml 复制代码
filters:
- name: RequestRateLimiter
  args:
	redis-rate-limiter.replenishRate: 10
	redis-rate-limiter.burstCapacity: 20
	redis-rate-limiter.requestedTokens: 1

RedirectTo根据请求头里包含的状态码重定向到某个地址

yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - RedirectTo=302, https://acme.org # 当请求头里包含302的状态码时重定向到该地址

RemoveRequestHeader表示删除请求中对应的请求头

yaml 复制代码
filters:
- RemoveRequestHeader=X-Request-Foo

RemoveRequestParameter表示删除请求中对应的请求参数

yaml 复制代码
filters:
- RemoveRequestParameter=red

RemoveResponseHeader表示删除响应中对应的响应头

yaml 复制代码
filters:
- RemoveResponseHeader=X-Response-Foo

RequestHeaderSize表示限制请求的请求头大小

yaml 复制代码
filters:
- RequestHeaderSize=1000B # 如果请求头超过1000B,则会发送431状态码

网关三大过滤器

路由过滤器

需求: 给所有进入userservice服务的请求都添加一个请求头如Truth=Hello World!,当前过滤器写在userservice服务下因此仅对当前路由的请求生效

yaml 复制代码
server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:80 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: user-service
          uri: lb://userservice # 配置userservice服务的路由规则
          predicates:
            - Path=/user/**
          filters:
            - AddRequestHeader=Truth,Hello World! # 添加请求头Truth,值是Hello World!

在UserController中编写对应的控制器方法获取请求头信息,重启网关服务和userservice服务并访问http://localhost:10010/user/test

java 复制代码
@GetMapping("/test")
public void test(@RequestHeader("Truth") String tmp) {
    System.out.println(tmp);
}

默认过滤器

默认过滤器: 如果希望过滤器的操作对所有的路由都生效,则可以将过滤器工厂写到spring.cloud.gateway.default-filters属性

yaml 复制代码
server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:80 # nacos地址
    gateway:
      routes:
        - id: user-service
          uri: lb://userservice
          predicates:
            - Path=/user/**
      default-filters: # 默认过滤器,对所有的路由请求都生效
        - AddRequestHeader=Truth,Hello World!

全局过滤器

全局过滤器和GatewayFilter一样都可以对进入网关的请求和微服务的响应做加工处理

  • GatewayFilter网关过滤器: 通过配置文件定义所以处理的逻辑是固定的且只有默认过滤器对所有路由请求生效
  • GlobalFilter全局过滤器: 可以编写代码做自己的业务逻辑,如登录状态判断,权限校验,请求限流等,对所有的路由请求都生效
java 复制代码
public interface GlobalFilter {
    /**
     *  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
     *
     * @param exchange 请求上下文,里面可以获取Request、Response等信息
     * @param chain 用来把请求委托给下一个过滤器 
     * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
     */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

需求: 定义全局过滤器拦截请求,判断请求参数中是否有authorization且参数值是否为admin, 如果同时满足则放行请求否则拦截

第一步: 在gateway模块下新建cn.itcast.gateway.filter包,然后编写AuthorizationFilter类实现GlobalFilter接口并重写其中的filter方法

java 复制代码
@Order(-1)
@Component
public class AuthorizationFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. 获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> params = request.getQueryParams();
        // 2. 获取authorization参数的值
        String authorization = params.getFirst("authorization");
        // 3. 校验
        if ("admin".equals(authorization)) {
            // 4. 满足需求则放行
            return chain.filter(exchange);
        }
        // 拦截请求
        // 5.1 先设置状态码,这里的常量底层就是401(在restFul中401表示未登录)
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        // 5.2 拦截请求
        return exchange.getResponse().setComplete();
    }
}

第二步: 重启网关测试我们的全局过滤器是否生效,只有访问http://localhost:10010/user/1?authorization=admin时可以看到正常数据

json 复制代码
{
    "id": 1,
    "username": "柳岩",
    "address": "湖南省衡阳市"
}

过滤器执行顺序

请求进入网关后会经过路由过滤器,DefaultFilter,GlobalFilter三类过滤器,它们本质都是GatewayFilter(GlobalFilter被封装在GatewayFilterAdapter中)

  • 请求路由后会将当前路由过滤器,DefaultFilter,GlobalFilter合并到一个过滤器链集合中,在集合中根据order值对每个过滤器排序后依次按顺序执行

过滤器必须指定一个int类型的order值,order值越小优先级越高即执行顺序越靠前(默认值为int最大值2147483647)

  • 路由过滤器和de默认过滤器的order值: 由Spring指定默认是按照声明顺序从1递增
  • 全局过滤器的order值: 通过实现Ordered接口实现getOrder()方法或者添加@Order注解来指定order值
java 复制代码
//@Order(-1)
@Component
public class AuthorizationFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. 获取请求参数
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2. 获取authorization参数
        String authorization = params.getFirst("authorization");
        // 3. 校验
        if ("admin".equals(authorization)) {
            // 4. 满足需求则放行
            return chain.filter(exchange);
        }
        // 5. 不满足需求,设置状态码,这里的常量底层就是401,在restFul中401表示未登录
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        // 6. 结束处理
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

过滤器的order值相同: 按照defaultFilter > routeFilter > GlobalFilter的顺序执行

  • org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法: 负责加载defaultFilters然后再加载某个路由过滤器最后合并
  • org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()方法: 负责加载全局过滤器最后与路由过滤器和默认过滤器合并
yaml 复制代码
# 配置路由过滤器和默认过滤器
server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:80 # nacos地址
    gateway:
      routes:
        - id: user-service
          uri: lb://userservice
          predicates:
            - Path=/user/**
          filters: # 路由过滤器默认是按照声明顺序从1递增
            - AddRequestHeader=Truth,Hello World! # order值为1
            - RemoveRequestHeader=X-Request-Foo # order值为2
      default-filters: # 默认过滤器
        - AddRequestHeader=Truth,Hello World! # order值为1
        - RemoveRequestHeader=X-Request-Foo # order值为2

# 将自定义的全局过滤器的order也设定为1
相关推荐
秃头佛爷1 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
阿伟*rui1 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
待磨的钝刨1 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck3 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei3 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师4 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉4 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer4 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq4 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端