Skip to content

Gateway - 网关

Gateway 官网链接

功能

Gateway 功能.png

原理

gateway 原理.png

依赖引入

也可以引入 loadbalancer 让网关负载均衡地分发请求

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

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

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
</dependencies>

基础配置

在 application.yml 配置全局跨域 以及请求路径前缀 /api/order/** ===> 转为 /**

yaml
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowed-origin-patterns: '*'
            allowed-headers: '*'
            allowed-methods: '*'
      routes:
        - id: order-route
          uri: lb://service-order
          predicates:
            - Path=/api/order/**
          filters:
            - RewritePath=/api/order/(?<segment>.*), /$\{segment}
        - id: product-route
          uri: lb://service-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/product/(?<segment>.*), /$\{segment}

路由配置源码

网关路由配置项即 RouteDefinition 类的属性

路由配置参数源码.png

断言 Predicate

Gateway 定义了一系列默认的断言工厂 gateway 断言工厂.png

自定义断言工厂

实现一个自定义断言工厂

java
@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {

    public VipRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        //localhost/search?q=haha&user=leifengyang
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                ServerHttpRequest request = serverWebExchange.getRequest();
                String first = request.getQueryParams().getFirst(config.param);
                if (StringUtils.hasText(first) && first.equals(config.value)) {
                    return true;
                }
                return false;
            }
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("param", "value");
    }

    @Data
    @Validated
    public static class  Config {

        @NotEmpty
        private String param;

        @NotEmpty
        private String value;
        
    }
    
}

断言包括 Path Query 还有自定义的 Vip 断言工厂

yaml
      routes:
        - id: bing-route
          uri: https://cn.bing.com/
          predicates:
            - name: Path
              args:
                patterns: /search
            - name: Query
              args:
                param: q
                regexp: haha
            - name: Vip
              args:
                param: user
                value: leifengyang
          order: 3

路径为 /search 参数为 q=haha Vip参数 user=leifengyang 就成功被断言 断言测试.png

过滤器

默认过滤器

将请求 /api/order/** 重写为 /**

yaml
        - id: order-route
          uri: lb://service-order
          predicates:
            - Path=/api/order/**
          filters:
            - RewritePath=/api/order/(?<segment>.*), /$\{segment}

全局过滤器

案例:定义全局过滤器记录所有请求处理花费时间

java
/**
 * 全局过滤器,记录请求时间与响应时间差
 */
@Component
@Slf4j
public class RtGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String uri = request.getURI().toString();
        long start = System.currentTimeMillis();
        log.info("请求【{}】开始:时间:{}",uri,start);
        //================ 以上前置逻辑 ===========

        Mono<Void> filter = chain.filter(exchange) // 放行 10s
                .doFinally((result) -> {
                    // 响应式编程 后置逻辑
                    long end = System.currentTimeMillis();
                    log.info("请求【{}】结束:时间:{},耗时:{}ms",uri,end,end-start);
                });

        return filter;
    }

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

自定义过滤器

自定义过滤器,每次响应之前添加一个一次性令牌,支持 uuid ,jwt 格式,可以在 yml 文件中配置

java
@Component
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //每次响应之前添加一个一次性令牌,支持 uuid ,jwt 等格式
                return chain.filter(exchange)
                        .then(Mono.fromRunnable(() -> {
                            ServerHttpResponse response = exchange.getResponse();
                            HttpHeaders headers = response.getHeaders();
                            String value = config.getValue();
                            if ("uuid".equalsIgnoreCase(value)) {
                                value = UUID.randomUUID().toString();
                            }
                            if ("jwt".equalsIgnoreCase(value)) {
                                value = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE2MjQyNjIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
                            }
                            headers.add(config.getName(),value);
                        }));
            }
        };
    }
    
}

application.yml 中配置自定义的过滤器 OnceToken 作为默认过滤器

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: order-route
          uri: lb://service-order
          predicates:
            - Path=/api/order/**
          filters:
            - RewritePath=/api/order/(?<segment>.*), /$\{segment}
          order: 0
      default-filters:
        - AddResponseHeader=X-Powered-By, Spring Cloud Gateway
        - OnceToken=X-Response-Token, jwt