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

注册中心使用的Eureka

1.创建模块

 

1.1创建模块cloud-gateway-gateway9527

1.2pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-gateway-gateway9527</artifactId>


    <dependencies>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


    </dependencies>

</project>

 

1.3yml文件

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由

        - id: payment_routh2   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get1/**   #断言,路径相匹配的进行路由


eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

关于gateway的route的配置说明

  id:路由的id,随便取,不要重复

  uri:实际的服务提供者的地址,也就是需要路由过去的地址

  predicates:断言,访问9527时,判断路径是否符合断言的规则。是,则进行路由。如:访问http://localhost:9527/payment/get/1。符合断言的匹配规则,此时进行路由,路由到http://localhost:8001/payment/get/1

 

1.4主启动类

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;


@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
    public static void main(String[] args) {
        SpringApplication.run(GatewayMain9527.class,args);
    }
}

 

1.5测试

  访问http://localhost:9527/payment/get/1

 

2.使用编码来配置gateway路由断言

这是上面在yml文件进行配置

 cloud:
    gateway:
      routes:
        - id: payment_routh   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由

 

也可以不这样配置,采用编码的方式来配置

package com.atguigu.springcloud.config;

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;

/**
 * @Classname GateWayConfig
 * @Description TODO
 * @Date 2021/5/14 0014 下午 2:39
 * @Created by jcc
 */

@Configuration
public class GateWayConfig {

    /*
    这里的配置相当于yml里面的配置
    gateway:
    routes:
            - id: path_rote_atguigu   #路由的ID,没有固定规则但要求唯一,建议配合服务名
    uri: http://news.baidu.com   #匹配后提供服务的路由地址---这里访问的是百度的新闻网站-用外网做下测试
    predicates:
            - Path=/guonei   #断言,路径相匹配的进行路由*/
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
    RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
    routes.route("path_rote_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com")).build();
    return routes.build();
     }

     //再配置一个
     @Bean
     public RouteLocator customRouteLocator2(RouteLocatorBuilder routeLocatorBuilder) {
         RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
         routes.route("path_rote_atguigu", r -> r.path("/guoji").uri("http://news.baidu.com")).build();
         return routes.build();
     }

}

  两种配置方式都可以。

 

3.配置动态路由

  上面配置路由,服务路径都是写的http://localhost:8001。如果这个服务是集群呢,难道去配置集群中的每一个服务吗?

   可以这样子来配置

   加入cloud: gateway: discovery: locator: enabled: true

   修改uri属性: uri: lb://cloud-payment-hystrix-service #服务在注册中心的名称。使用服务名称来代替地址

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment_routh   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-hystrix-service   #服务在注册中心的名称
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由

        - id: payment_routh2   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-hystrix-service   #服务在注册中心的名称
          predicates:
            - Path=/payment/get1/**   #断言,路径相匹配的进行路由


eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

 

4.断言

4.1断言工厂

  官方提供了11种

  

 

4.1.1The After Route Predicate Factory

 

 - After=2017-01-20T17:42:47.789-07:00[America/Denver] 表示在某个时间之后开始生效(这里是美国时间,可有使用国内时间) 

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

 

4.1.2The Before Route Predicate Factory

- Before=2017-01-20T17:42:47.789-07:00[America/Denver]  表示在某个时间之前有效
spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

 

4.1.3 The Between Route Predicate Factory

 - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] 在这段时间内有效
spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: https://example.org
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

4.1.4 The Cookie Route Predicate Factory

 

 - Cookie=chocolate, ch.p   必须携带cookie,名称为chocolate,值和正则表达式ch.p匹配
spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=chocolate, ch.p

 

 

 

4.1.5 The Header Route Predicate Factory

 

- Header=X-Request-Id, \d+  请求具有名为X-Request-Id,其值与\d+正则表达式匹配的标头

 

 

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

 

 4.1.6The Host Route Predicate Factory

 - Host=**.somehost.org,**.anotherhost.org    请求的Host标头值为www.somehost.orgbeta.somehost.org或,则此路由匹配www.anotherhost.org
spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

 

4.1.7 The Method Route Predicate Factory

- Method=GET,POST  请求方式为GET 或者 POST
spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST

 

4.1.8The Path Route Predicate Factory

- Path=/red/{segment},/blue/{segment}  路径匹配
spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

 

4.1.9 The Query Route Predicate Factory

- Query=green  请求包含green查询参数
spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green

 

4.1.10The RemoteAddr Route Predicate Factory

 - RemoteAddr=192.168.1.1/24   请求方的ip匹配  192.168.1.1  到 192.168.1.24
spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

 

4.1.11The Weight Route Predicate Factory

- Weight=group1, 2   将大约80%的流量转发到weighthigh.org,将大约20%的流量转发weightlow.org。相当于负载均衡的配置

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

 

4.2组合配置

 - Path=/payment/get/**   #断言,路径相匹配的进行路由
 - AFTER=2022-01-20T17:42:47.485-08:00[Asia/Shanghai]  #断言  时间在2022-01-20 17:42:47 后生效
在2022-01-20 17:42:47之后,路径匹配符合 /payment/get/**的请求断言判定成功
      routes:
        - id: payment_routh   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-hystrix-service   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由
            - AFTER=2017-01-20T17:42:47.485-08:00[Asia/Shanghai]

 

5. Filter(转https://blog.csdn.net/forezp/article/details/85057268)

5.1filter基本

当我们有很多个服务时,比如下图中的user-service、goods-service、sales-service等服务,客户端请求各个服务的Api时,每个服务都需要做相同的事情,比如鉴权、限流、日志输出等。

 


对于这样重复的工作,有没有办法做的更好,答案是肯定的。在微服务的上一层加一个全局的权限控制、限流、日志输出的Api Gatewat服务,然后再将请求转发到具体的业务服务层。这个Api Gateway服务就是起到一个服务边界的作用,外接的请求访问系统,必须先通过网关层。

 


5.2生命周期
Spring Cloud Gateway同zuul类似,有“pre”(请求前)和“post”(请求后)两种方式的filter。客户端的请求先经过“pre”类型的filter,然后将请求转发到具体的业务服务,比如上图中的user-service,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端

 

 

 与zuul不同的是,filter除了分为“pre”和“post”两种方式的filter外,在Spring Cloud Gateway中,filter从作用范围可分为另外两种,一种是针对于单个路由的gateway filter,它在配置文件中的写法同predict类似;另外一种是针对于所有路由的global gateway filer。现在从作用范围划分的维度来讲解这两种filter

5.3Gateway Filter

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

5.3.1介绍

  过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。过滤器可以限定作用在某些特定请求路径上。 Spring Cloud Gateway包含许多内置的GatewayFilter工厂。
  GatewayFilter工厂是在配置文件application.yml中配置,遵循了约定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名称,而不需要写全部的类名,比如AddRequestHeaderGatewayFilterFactory只需要在配置文件中写AddRequestHeader,而不是全部类名。在配置文件中配置的GatewayFilter Factory最终都会相应的过滤器工厂类处理。
Spring Cloud Gateway 内置的过滤器工厂一览表如下

 

 

 

 

  现在挑几个常见的过滤器工厂来讲解,每一个过滤器工厂在官方文档都给出了详细的使用案例,如果不清楚的还可以在org.springframework.cloud.gateway.filter.factory看每一个过滤器工厂的源码。

 5.3.2截个filter介绍

  1)AddRequestHeader GatewayFilter Factory
  创建工程,gateway依赖如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

 

在工程的配置文件中,加入以下的配置

 

filters:
            - AddRequestHeader=X-Request-red, blue

 

完整配置

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment_routh   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-hystrix-service   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由
            - After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
          filters:
            - AddRequestHeader=X-Request-red, blue

        - id: payment_routh2   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-hystrix-service   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get1/**   #断言,路径相匹配的进行路由
            - After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
          filters:
            - AddRequestHeader=X-Request-red, blue



eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

 

 

  配置了一个filter为AddRequestHeaderGatewayFilterFactory(约定写成AddRequestHeader),AddRequestHeader过滤器工厂会在请求头加上一对请求头,名称为X-Request-Foo,值为Bar。为了验证AddRequestHeaderGatewayFilterFactory是怎么样工作的,查看它的源码,AddRequestHeaderGatewayFilterFactory的源码如下:

public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .header(config.getName(), config.getValue())
                    .build();

            return chain.filter(exchange.mutate().request(request).build());
        };
    }

}

由上面的代码可知,根据旧的ServerHttpRequest创建新的 ServerHttpRequest ,在新的ServerHttpRequest加了一个请求头,然后创建新的 ServerWebExchange ,提交过滤器链继续过滤

  测试访问

   在服务提供方代码修改

@GetMapping(value = "/payment/get1/{id}")
    public String create(@PathVariable("id") Long id,HttpServletRequest request){
        String header = request.getHeader("X-Request-red");
        System.out.println(header);
        return paymentService.paymentInfo_OK(id);
    }

 

  访问

  

 

 

   服务提供方控制台打印blue,说明请求头中X-Request-red:blue成功添加

 

 

 

 

 

跟AddRequestHeader过滤器工厂类似的还有AddResponseHeader过滤器工厂,在此就不再重复

 2)RewritePath GatewayFilter Factory

  在Nginx服务启中有一个非常强大的功能就是重写路径,Spring Cloud Gateway默认也提供了这样的功能,这个功能是Zuul没有的。在配置文件中加上以下的配置

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://blog.csdn.net
        predicates:
        - Path=/foo/**
        filters:
        - RewritePath=/foo/(?<segment>.*), /$\{segment}

 

 

 

 

  上面的配置中,所有的/foo/**开始的路径都会命中配置的router,并执行过滤器的逻辑,在本案例中配置了RewritePath过滤器工厂,此工厂将/foo/(?.*)重写为{segment},然后转发到https://blog.csdn.net。比如在网页上请求localhost:8081/foo/forezp,此时会将请求转发到https://blog.csdn.net/forezp的页面,比如在网页上请求localhost:8081/foo/forezp/1,页面显示404,就是因为不存在https://blog.csdn.net/forezp/1这个页面

 

5.4自定义GatewayFilter过滤器

  https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#global-filters 

   Spring Cloud Gateway内置了多种强大的过滤器工厂,能够满足很多场景的需求,那么能不能自定义自己的过滤器呢,当然是可以的。

 1)在spring Cloud Gateway中,过滤器需要实现GatewayFilter和Ordered2个接口。写一个RequestTimeGatewayFilter ,代码如下

package com.atguigu.springcloud.filter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @Classname RequestTimeFilter
 * @Description TODO
 * @Date 2021/5/17 0017 下午 2:28
 * @Created by jcc
 */
@Component
public class RequestTimeGatewayFilter implements GatewayFilter, Ordered {

    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                    if (startTime != null) {
                        log.info("myfilter:   " + exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
                    }
                })
        );

    }

    @Override
    public int getOrder() {
        return 0;
    }
}

 

在上面的代码中,Ordered中的int getOrder()方法是来给过滤器设定优先级别的,值越大则优先级越低。还有有一个filterI(exchange,chain)方法,在该方法中,先记录了请求的开始时间,并保存在ServerWebExchange中,此处是一个“pre”类型的过滤器,然后再chain.filter的内部类中的run()方法中相当于"post"过滤器,在此处打印了请求所消耗的时间。

  2)把这个过滤器加入到过滤工厂,并且添加到Spring容器中

 

package com.atguigu.springcloud.config;

import com.atguigu.springcloud.filter.RequestTimeGatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @Classname FilterConfig
 * @Description TODO
 * @Date 2021/5/17 0017 下午 2:29
 * @Created by jcc
 */
@Component
public class RequestTimeGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {

        @Override
        public GatewayFilter apply(Object config)
        {
            return new RequestTimeGatewayFilter();
        }

}

 


查看GatewayFilterFactory的源码,可以发现GatewayFilterfactory的层级如下:

 

 

 
过滤器工厂的顶级接口是GatewayFilterFactory,有2个两个较接近具体实现的抽象类,分别为AbstractGatewayFilterFactory和AbstractNameValueGatewayFilterFactory,这2个类前者接收一个参数,比如它的实现类RedirectToGatewayFilterFactory;后者接收2个参数,比如它的实现类AddRequestHeaderGatewayFilterFactory类。现在需要将请求的日志打印出来,需要使用一个参数,这时可以参照RedirectToGatewayFilterFactory的写法

 

 

  3)yml中配置

 filters:- RequestTime

   完整配置

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment_routh   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-hystrix-service   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由
            - After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
          filters:
            - AddRequestHeader=X-Request-red, blue
            - RequestTime

        - id: payment_routh2   #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-hystrix-service   #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get1/**   #断言,路径相匹配的进行路由
            - After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
          filters:
            - AddRequestHeader=X-Request-red, blue
            - RequestTime



eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

 

 

测试 :

控制台打印:

 

 

5.5 global filter

 Spring Cloud Gateway根据作用范围划分为GatewayFilter和GlobalFilter,二者区别如下:

    GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上

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

Spring Cloud Gateway框架内置的GlobalFilter如下:

 

 

 上图中每一个GlobalFilter都作用在每一个router上,能够满足大多数的需求。但是如果遇到业务上的定制,可能需要编写满足自己需求的GlobalFilter。

5.6自定义GlobalFilter

在下面的案例中将讲述如何编写自己GlobalFilter,该GlobalFilter会校验请求中是否包含了请求参数“token”,如何不包含请求参数“token”则不转发路由,否则执行正常的逻辑。代码如下:

public class TokenFilter implements GlobalFilter, Ordered {

    Logger logger=LoggerFactory.getLogger( TokenFilter.class );
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            logger.info( "token is empty..." );
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

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

注入spring

@Configuration
public class FilterConfig {

    @Bean
    public TokenFilter tokenFilter(){
        return new TokenFilter();
    }
}

 测试访问

  

 

   由于没有带token,被拦截了,控制台打印