0201概述-网关Gateway-微服务架构

1 前言

Spring Cloud Gateway是一个基于Spring Framework 5、Spring Boot 2和Project Reactor等技术开发的API网关它提供了一系列的过滤器Filter来处理HTTP请求和响应可以轻松地实现路由、负载均衡、限流、重试、熔断、安全控制等功能可以作为微服务架构中的入口和边缘服务。

Spring Cloud Gateway的核心组件包括路由Route、断言Predicate、过滤器Filter等。路由用来将请求映射到不同的微服务上断言则用来匹配请求的条件过滤器则可以对请求进行修改和拦截。

Spring Cloud Gateway提供了丰富的可扩展性可以通过编写自定义的路由、断言、过滤器等组件来满足各种复杂的业务需求。同时它还集成了Spring Cloud的服务发现和负载均衡机制可以自动地从注册中心中获取微服务的信息并进行负载均衡

下面我们根据官网文档和我们正在学习的开源项目pig文档以及其他相关文档介绍一些我们开发中会用到的一些内容。

2 项目引入

项目工程pom.xml文件用引入

<!-- 版本在spring-cloud-gateway-dependencies中指定 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

3 术语

核心概念描述
Route路由网关最基本的模块。它由一个 ID、一个目标 URI、一组断言Predicate和一组过滤器Filter组成。
Predicate断言路由转发的判断条件我们可以通过 Predicate 对 HTTP 请求进行匹配例如请求方式、请求路径、请求头、参数等如果请求与断言匹配成功则将请求转发到相应的服务。
Filter过滤器过滤器我们可以使用它对请求进行拦截和修改还可以使用它对上文的响应进行再处理。

注意其中Route和Predicate必须同时申明

4 工作原理

gateway工作原理如下图4-1所示

在这里插入图片描述

Spring Cloud Gateway是Spring Cloud生态系统中的一个API网关服务它基于Spring 5Spring Boot 2和Project Reactor构建提供了一种简单而有效的方式来路由请求、进行限流、进行身份验证和授权、实现负载均衡等功能。

Spring Cloud Gateway的工作原理可以简单概括如下

  1. 路由规则配置开发人员通过配置文件或代码配置路由规则定义请求的匹配规则和目标服务的位置。
  2. 请求到达网关客户端请求到达Spring Cloud Gateway被路由到对应的处理器。
  3. 过滤器链处理Spring Cloud Gateway通过一系列过滤器链处理请求每个过滤器可以进行一些操作如修改请求头、重定向、转发、限流、身份验证等。
  4. 路由转发根据路由规则将请求转发到对应的目标服务可以是Spring Boot应用程序、其他微服务或外部API。
  5. 响应处理Spring Cloud Gateway收到目标服务的响应后可以通过过滤器链对响应进行修改然后将响应返回给客户端。

总之Spring Cloud Gateway作为一种轻量级的API网关服务可以通过路由规则和过滤器链处理请求将请求转发到目标服务并处理响应从而为微服务架构中的应用提供了一种高效、灵活和可扩展的解决方案。

5 配置示例

5.1 简洁配置

application.xml配置示例

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

5.2 展开配置

application.xml配置示例

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

6 Predicate

路由转发判断条件可以根据很多信息去判断包括时间、Cookie、Header、Host、Method、Path等等。

我们这里以开发中的常用的Path为例示例如下

routes:
  - id: admin-service_router
    uri: lb://admin-service
    predicates:
      - Path=/admin/**
    filters:
      - StripPrefix=1
  • /admin/****表示任意,匹配任意一级路径是admin的请求转发到对应的uri

7 GatewayFilter

网关过滤器可以对HTTP请求或者响应做修改。下面介绍2个开发用常用的网关过滤器

  • StripPrefix忽略前缀
  • RequestRateLimiter请求限流

7.1 StripPrefix GatewayFilter

以#6中路由配置为例讲解后面参数为数字表示在向下转发的时候忽略几段路径前缀。

routes:
  - id: admin-service_router
    uri: lb://admin-service
    predicates:
      - Path=/admin/**
    filters:
      - StripPrefix=1
  • 这里stripPrefix值为1对应的请求示例/admin/user在向下转发的时候忽略掉/admin/变为/user
  • 路径分隔符默认/StripPrefix值对应几个/xxx/分隔符包围的路径。

7.2 RequestRateLimiter GatewayFilter

网关限流实例

① pom 依赖

这里一定要注意是网关引入的redis-reactive背压模式的redis。

<!--基于 reactive stream 的redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

② 配置按照请求IP 的限流

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: lb://pig-upms
        order: 10000
        predicates:
        - Path=/admin/**
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1  # 令牌桶每秒填充平均速率
            redis-rate-limiter.burstCapacity: 3  # 令牌桶总容量
            key-resolver: "#{@remoteAddrKeyResolver}" #SPEL表达式去的对应的bean
        - StripPrefix=1
  • 配置bean多维度限流量的入口 对应上边key-resolver
/**
* 自定义限流标志的key多个维度可以从这里入手
* exchange对象中获取服务ID、请求信息用户信息等
*/
@Bean
KeyResolver remoteAddrKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}

6 Global Filters

全局过滤器配合Ordered接口用来指定在过滤器执行链中的顺序。在开发中我们一般用来做日志记录获取自定义请求头信息做校验等等。

下面看下日志记录的实例

@Slf4j
@Component
public class ApiLoggingFilter implements GlobalFilter, Ordered {

   private static final String START_TIME = "startTime";

   private static final String X_REAL_IP = "X-Real-IP";// nginx需要配置

   @Override
   public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      if (log.isDebugEnabled()) {
         String info = String.format("Method:{%s} Host:{%s} Path:{%s} Query:{%s}",
               exchange.getRequest().getMethod().name(), exchange.getRequest().getURI().getHost(),
               exchange.getRequest().getURI().getPath(), exchange.getRequest().getQueryParams());
         log.debug(info);
      }
      exchange.getAttributes().put(START_TIME, System.currentTimeMillis());
      return chain.filter(exchange).then(Mono.fromRunnable(() -> {
         Long startTime = exchange.getAttribute(START_TIME);
         if (startTime != null) {
            Long executeTime = (System.currentTimeMillis() - startTime);
            List<String> ips = exchange.getRequest().getHeaders().get(X_REAL_IP);
            String ip = ips != null ? ips.get(0) : null;
            String api = exchange.getRequest().getURI().getRawPath();

            int code = 500;
            if (exchange.getResponse().getStatusCode() != null) {
               code = exchange.getResponse().getStatusCode().value();
            }
            // 当前仅记录日志后续可以添加日志队列来过滤请求慢的接口
            if (log.isDebugEnabled()) {
               log.debug("来自IP地址{}的请求接口{}响应状态码{}请求耗时{}ms", ip, api, code, executeTime);
            }
         }
      }));
   }

   @Override
   public int getOrder() {
      return Ordered.LOWEST_PRECEDENCE;
   }

}

7 网关超时配置

路由超时配置可以为所有路由配置Http超时响应和连接并为每个特定路由覆盖Http超时。

7.① 配置全局路由超时时间

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 10s
  • connect-timeout 必须以毫秒为单位指定连接超时时间.
  • response-timeout 必须指定为java.time.Duration

7.② 特定接口配置超时时间

- id: pig-upms      # 唯一的服务ID
  uri: lb://pig-upms # 注册中心的服务名称实现负载均衡
  predicates:
  - Path=/admin/demo  #所有业务的请求前缀
  metadata:
    response-timeout: 200
    connect-timeout: 200

可以通过路由的metadata以下两个参数配置每个路由超时

  • connect-timeout 必须以毫秒为单位指定连接超时时间.
  • response-timeout 必须以毫秒为单位指定响应超时时间.

8 网关CORS 跨域配置

CORS跨域配置可以以不同的方式进行配置这里介绍在网关进行配置的方式。

在网关的配置文件中加入以下内容(请根据实际情况修改)

spring:
  cloud:
    gateway:
#      default-filters:
#        - DedupeResponseHeader=Access-Control-Allow-Origin
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOriginPatterns: "*"           #注意这个设置只对 spring boot 2.4+ 有效低版本 使用  allowedOrigins: "*" 属性
            allowed-methods: "*"
            allowed-headers: "*"
            allow-credentials: true
            exposedHeaders: "Content-Disposition,Content-Type,Cache-Control"
  • 以上配置可作为开发环境使用生成环境建议你根据实际情况修改请先理解CORS并参考org.springframework.cloud.gateway.config.GlobalCorsProperties
  • 跨域时会产生预检请求(Pre-Flight Request)这样就会对你的服务器产生额外的网络请求。如果可以通过部署手段解决跨域则可以关闭跨域支持方法是把以上配置信息清理掉。

结语

如果小伙伴什么问题或者指教欢迎交流。

❓QQ:806797785

⭐️源代码仓库地址https://gitee.com/gaogzhen/micro

参考地址

[1] springcloud gateway 官方文档

[2] GatewaySpring Cloud API网关组件非常详细

[3] Spring Cloud——微服务网关Spring Cloud GateWay

[4] lengleng /pig

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6