目录

前言

一、如何使用网关?

二、网关特性

三、工作流程

四、配置路由

五、配置断言 

六、配置过滤器

七、自定义网关全局过滤器

八、在网关层配置请求超时

 九、使用基于注册中心的路由配置

十、在网管层配置跨域

总结


前言

Spring Cloud Gateway提供了一个构建在 Spring 生态之上的 API Gateway,包括:Spring 5、Spring Boot 2 和 Project Reactor。  Spring Cloud Gateway 旨在提供一种简单而有效的方式来路由到 API,并为它们提供横切关注点,例如:安全性、监控/指标和弹性。


一、如何使用网关?

要在项目中使用 Spring Cloud Gateway,需要引入 ID 为 org.springframework.cloud 和工件 ID 为 spring-cloud-starter-gateway 的 starter。 有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参阅 Spring Cloud 项目页面。 如果包含启动器,但不希望启用网关,请设置 spring.cloud.gateway.enabled=false。

二、网关特性

  1. 路由:网关的基本构建块。  它由 ID、目标 URI、断言集合和过滤器集合定义。  如果聚合断言为真,则匹配路由,将请求转发到对应的URI,此外,如果配置了过滤器,则转发之前先会进行过滤器过滤。
  2. 断言:这是一个 Java 8 函数Predicate。这使您可以匹配来自 HTTP 请求的任何内容,例如标头或参数。只有当断言为真时,网关才会将请求转发到对应的URI地址
  3. 过滤器:这些是使用特定工厂构建的 GatewayFilter 实例。  在这里,您可以在发送下游请求之前或之后修改请求和响应。

三、工作流程

spring cloud gateway签名方式 spring cloud gateway教程_Cloud

首先,客户端向 Spring Cloud Gateway 发出请求。  然后,网关根据请求去查找路由配置,如果存在匹配的路由,则将该请求放行到过滤器链中,经过一系列过滤操作之后,将请求发送到对应UR地址的服务的对应Controller处理。

四、配置路由

routes属性对应着一个List<RouteDefinition> routes 用来管理所有的路由配置,其中,RouteDefinition拥有6个配置属性,具体如下:

@Validated
public class RouteDefinition {
    private String id;
    private @NotEmpty @Valid List<PredicateDefinition> predicates = new ArrayList();
    private @Valid List<FilterDefinition> filters = new ArrayList();
    private @NotNull URI uri;
    private Map<String, Object> metadata = new HashMap();
    private int order = 0;
}

一般来说,我们配置一个路由时至少需要配置id、uri两项,参考如下:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org

五、配置断言 

Spring Cloud Gateway 将路由匹配为 Spring WebFlux HandlerMapping 基础设施的一部分。  Spring Cloud Gateway 包含许多内置的路由断言工厂。  所有这些断言都匹配 HTTP 请求的不同属性。  我们可以将多个路由断言工厂与逻辑和语句结合起来。至于我们需要配置什么样的断言,以及可以选择哪些断言,我们可以参考Spring Cloud Gateway 的断言工厂

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

六、配置过滤器

网关路由过滤器允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。  路由过滤器的范围是特定的路由。  Spring Cloud Gateway 包含许多内置的 GatewayFilter 工厂。

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue

在配置文件中配置路由过滤器需要注意每个过滤器需要两个参数,第一个为name也可以称之为key

第二个为value,比如上面的AddRequestHeader路由过滤器就是在请求头中添加一个name为

X-Request-red,value为blue的属性。至于有哪些路由过滤器可以选择,我们可以参考Spring Cloud Gateway的GatewayFilter路由过滤器工厂

七、自定义网关全局过滤器

网关的全局过滤器GlobleFilter不同于路由过滤器GatewayFilter的是,全局过滤器作用于所有经过网关的请求,而路由过滤器则作用于所归属的路由。两个作用范围不同,此外,路由过滤器GatewayFilter比全局过滤器GlobleFilter多了两个namevalue属性,源码如下:

public interface GlobalFilter {
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}


public interface GatewayFilter extends ShortcutConfigurable {
    String NAME_KEY = "name";
    String VALUE_KEY = "value";

    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

结合自定义全局过滤器分析请求过程:当一个请求过来时,首先会通过断言规则去路由集合中匹配路由,如果匹配上了,则进入过滤器链,网关会将该路由下配置的路由过滤器和全局过滤器都纳入到滤器链中,并根据过滤器的顺序逐个执行过滤器,至于顺序该如何设定,我们可以在过滤器上使用注解@Order(100)在其中指定一个数字,数字越大越晚执行,如果为负数则最晚执行;或者实现Ordered接口。参口如下:

@Component
@Order(100)
public class CustomeGlobleFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // do something
        return null;
    }
}

 Spring Cloud Gateway网关已经为我们提供了一些现成的全局过滤器,具体可以参考Gateway网关提供的全局过滤器,但一般来说,我们都会通过实现GlobleFilter接口来实现符合自己需求的全局过滤器。

八、在网关层配置请求超时

1、全局设置

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 2    # 连接超时2秒
        response-timeout: 3000    # 响应超时3秒

2、基于路由局部配置

spring:
  cloud:
    gateway:
      routes:
        - id: per_route_timeouts
          uri: https://example.org
          predicates:
            - name: Path
              args:
                pattern: /delay/{timeout}
          metadata:
            response-timeout: 200
            connect-timeout: 200

 九、使用基于注册中心的路由配置

首先,gateway网关服务必须注册到注册中心,其次,需要在配置文件中添加如下配置开启该功能

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true

然后我们就使用基于serviceId的路由配置,具体可以如下配置路由:

spring:
  cloud:
    gateway:
      routes:
        - id: gulimall-product
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - StripPrefix=1

其中id配置的是注册中心中对应服务的为服务名、uri中的 lb 前缀代表负载均衡,使用的是 loadbalancer 组件,predicates使用的是路径匹配,意为,当请求的的地址与该路径匹配时,通过负载均衡从注册中心拿到服务的host地址,然后将请求的host替换成从注册中心拿到的hsot,这样就可以实现从网关host替换成对应服务的hsot;此外,过滤器中的StripPrefix=1意为剔除路径的首节路径地址,例如,假设8888端口为网关端口,一个http://127.0.0.1:8888/api/product/selectAll请求,会先到网关,然后根据地址去匹配路由,假设有路由断言为Path=/api/product/**则该请求就匹配上了该路由,然后,网关会根据id名去注册中心里查找服务并拿到他的host地址,然后,将原来网关的host替换成拿到的host地址,假设拿到的host为http://127.0.0.1:8882,则新的地址为http://127.0.0.1:8882/api/product/selectAll,然后该请求进入过滤器链,StripPrefix=1过滤操作将从原有请求地址中剔除首个前缀/api从而变为http://127.0.0.1:8882/product/selectAll,

十、在网管层配置跨域

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

@Configuration
public class CorsConfig {
    // 该配置适用于reactive响应式环境,注意导包不要到错了
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        // 设置允许携带cookie
        config.setAllowCredentials(true);
        // 设置允许的最大跨域时间 3秒
        config.setMaxAge(3000L);

        // 必须是reactive包下的UrlBasedCorsConfigurationSource 
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

总结

Spring Cloud Gateway网关作为我们开发过程经常使用的微服务组件,我们有必要对他的一些常用方式进行总结,以此来应对快速开发,因为,有些用法都是固定的,所以,我希望在以后使用网关的过程中能够直接拿来就用,而不是耗费大量时间在查找资料上,同时,也希望诸君能够从这篇文章受益。