美文网首页Gatewayspring cloud
网关Spring Cloud Gateway

网关Spring Cloud Gateway

作者: 勤_ | 来源:发表于2021-08-17 11:54 被阅读0次

概述

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

  • Route: The basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates, and a collection of filters. A route is matched if the aggregate predicate is true.
  • Predicate: This is a Java 8 Function Predicate. The input type is a Spring Framework ServerWebExchange. This lets you match on anything from the HTTP request, such as headers or parameters.
  • Filter: These are instances of GatewayFilter that have been constructed with a specific factory. Here, you can modify requests and responses before or after sending the downstream request.
spring_cloud_gateway_diagram.png

依赖的框架以及版本

工具 版本
spring-boot 2.5.0
spring-cloud 2020.0.1
Spring Cloud Alibaba 2021.1
nacos 2.0.3

实现步骤

1,spring cloud gateway与nacos集成两步~

  • 添加依赖

    <properties>
       <java.version>1.8</java.version>
       <spring-cloud.version>2020.0.1</spring-cloud.version>
       <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
    </properties>
    <dependencies>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-webflux</artifactId>
       </dependency>
       <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-gateway</artifactId>
       </dependency>
       <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <optional>true</optional>
       </dependency>
       <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
       </dependency>
       <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-loadbalancer</artifactId>
       </dependency>
    </dependencies>
    <dependencyManagement>
       <dependencies>
          <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-dependencies</artifactId>
             <version>${spring-cloud.version}</version>
             <type>pom</type>
             <scope>import</scope>
          </dependency>
          <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-alibaba-dependencies</artifactId>
             <version>${spring-cloud-alibaba.version}</version>
             <type>pom</type>
             <scope>import</scope>
          </dependency>
       </dependencies>
    </dependencyManagement>
    
  • 配置application.yml文件,无需配置到bootstrap.yml文件中了,新版本nacos配置会报错。

    spring:
      application:
        name: gateway
      cloud:
        gateway:
          discovery:
            locator:
              enabled: true
              lower-case-service-id: true
    #      routes:
    #        - id: header_route
    #          uri: lb://archetype
    #          predicates:
    #            - Header=X-Request-Id, \d+
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848
            namespace: lqd
            password: nacos
            username: nacos
    
  • Postman验证:

    image-20210817094935112.png

2,了解下Route、Predicates、Filter

  • Route、Predicates 验证:Route Predicate Factories The Header Route Predicate Factory 请求头过滤添加如下配置,通过Postman请求验证

    routes:
      - id: header_route
        uri: lb://archetype
        predicates:
          - Header=X-Request-Id, \d+
    
    image-20210817095807823.png image-20210817095846592.png
  • Filter验证The AddResponseHeader GatewayFilter Factory

    routes:
      - id: header_route
        uri: lb://archetype
        predicates:
          - Header=X-Request-Id, \d+
        filters:
          - AddResponseHeader=X-Response-TIME, 20210817
    
    image-20210817103422397.png

关键源码

Predicate的核心类RoutePredicateHandlerMapping、AbstractRoutePredicateFactory

  • RoutePredicateHandlerMapping

    protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
       return this.routeLocator.getRoutes()
             // individually filter routes so that filterWhen error delaying is not a
             // problem
             .concatMap(route -> Mono.just(route).filterWhen(r -> {
                // add the current route we are testing
                exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                return r.getPredicate().apply(exchange);
             })
                   // instead of immediately stopping main flux due to error, log and
                   // swallow it
                   .doOnError(e -> logger.error("Error applying predicate for route: " + route.getId(), e))
                   .onErrorResume(e -> Mono.empty()))
             // .defaultIfEmpty() put a static Route not found
             // or .switchIfEmpty()
             // .switchIfEmpty(Mono.<Route>empty().log("noroute"))
             .next()
             // TODO: error handling
             .map(route -> {
                if (logger.isDebugEnabled()) {
                   logger.debug("Route matched: " + route.getId());
                }
                validateRoute(route, exchange);
                return route;
             });
    
       /*
        * TODO: trace logging if (logger.isTraceEnabled()) {
        * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
        */
    }
    

Filter核心类DefaultGatewayFilterChain、核心接口GlobalFilter、代理请求转发类NettyRoutingFilter

  • DefaultGatewayFilterChain这个类可以看到springCloud的Filter的责任链。
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
   return Mono.defer(() -> {
      if (this.index < filters.size()) {
         GatewayFilter filter = filters.get(this.index);
         DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
         return filter.filter(exchange, chain);
      }
      else {
         return Mono.empty(); // complete
      }
   });
}

例如:RouteToRequestUrlFilter通过这个类可以方便查看到路由后的访问路径。

  • NettyRoutingFilter这个类是gateway转发服务到代理服务的处理类

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
       URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
    
       String scheme = requestUrl.getScheme();
       if (isAlreadyRouted(exchange) || (!"http".equals(scheme) && !"https".equals(scheme))) {
          return chain.filter(exchange);
       }
       setAlreadyRouted(exchange);
    
       ServerHttpRequest request = exchange.getRequest();
    
       final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
       final String url = requestUrl.toASCIIString();
    
       HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange);
    
       final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
       filtered.forEach(httpHeaders::set);
    
       boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);
       Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
    
       Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange).headers(headers -> {
          headers.add(httpHeaders);
          // Will either be set below, or later by Netty
          headers.remove(HttpHeaders.HOST);
          if (preserveHost) {
             String host = request.getHeaders().getFirst(HttpHeaders.HOST);
             headers.add(HttpHeaders.HOST, host);
          }
       }).request(method).uri(url).send((req, nettyOutbound) -> {
          if (log.isTraceEnabled()) {
             nettyOutbound.withConnection(connection -> log.trace("outbound route: "
                   + connection.channel().id().asShortText() + ", inbound: " + exchange.getLogPrefix()));
          }
          return nettyOutbound.send(request.getBody().map(this::getByteBuf));
       }).responseConnection((res, connection) -> {
    ......
    
       return responseFlux.then(chain.filter(exchange));
    }
    

异常报错

1,出现503 Service Unavailable

解决方法:增加spring-cloud-starter-loadbalancer依赖

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

参考

spring cloud 与 spring cloud alibaba 版本对应关系
spring cloud gateway
Reactor 3
Spring 5 WebFlux
例子

相关文章

网友评论

    本文标题:网关Spring Cloud Gateway

    本文链接:https://www.haomeiwen.com/subject/lmnbbltx.html