API网关-SpringCloud Gateway

Spring Cloud Gateway是一个基于Spring Framework的开源API网关,用于构建微服务架构中的统一访问层。它充当了应用程序和后端服务之间的代理,提供了路由、负载均衡、安全性、监控等功能,以简化微服务架构中的网络请求管理和流量控制。

Spring Cloud Gateway的主要特点包括:

  1. 动态路由: 可以根据请求的信息将流量路由到不同的后端服务,支持动态添加、删除和修改路由规则。
  2. 负载均衡: 可以自动分配流量到多个实例,以提高系统的可用性和性能。
  3. 断路器模式: 提供了断路器模式来处理后端服务的故障,防止故障服务对整个系统的影响。
  4. 过滤器: 可以在请求和响应之间应用一系列的过滤器,用于修改请求、响应或执行一些预处理/后处理操作。
  5. 限流和速率控制: 可以通过配置限制每个路由或服务的请求速率,以防止过载和滥用。
  6. 安全性: 可以集成Spring Security等安全框架,对请求进行认证和授权。
  7. 监控和日志: 提供了监控和日志功能,帮助开发人员了解流量和系统的状态。
  8. 易于扩展: 由于基于Spring Framework构建,因此可以通过自定义插件和过滤器来扩展其功能。

SpringCloud Gateway简单使用

  • 添加依赖: 在生成的pom.xml文件中,添加Spring Cloud Gateway的依赖。通常,您需要添加以下依赖:

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    因为我们使用了nacos实现服务注册与服务发现,所以也要引入nacos相关的依赖,如果不需要可以不引入,routes.uri直接指定目标服务的完整URL字符串。

    1
    2
    3
    4
    5
      <!--nacos服务发现依赖-->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
  • 配置路由:application.ymlapplication.properties中配置您的路由规则。以下是一个简单的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    server:
    port: 10010
    spring:
    application:
    name: gateway
    gateway:
    routes:
    # 路由标示,必须唯一
    - id: user-service
    # 路由的目标地址
    uri: lb://user-service
    # 路由断言,判断请求是否符合规则
    predicates:
    # 路径断言,判断路径是否是以/user开头,如果是则符合
    - Path=/user/**
    filter:
    #添加路由过滤器
    - AddRequestHeader=Tag,userRequest
    - id: order-service
    uri: lb://order-service
    predicates:
    - Path=/order/**
    #添加default过滤器
    default-filters:
    - AddRequestHeader=origin,gateway
    1. 直接URL字符串: 最简单的写法就是直接指定目标服务的完整URL字符串。

      uri: http://example.com

    2. lb协议: 使用lb协议可以通过服务发现来进行负载均衡,将请求分发到不同实例。

      uri: lb://service-name

    3. lb协议 + 负载均衡策略: 可以在lb协议后面添加负载均衡策略,如lb://service-name?lbMethod=ROUND_ROBIN

      uri: lb://service-name?lbMethod=ROUND_ROBIN

    4. 使用自定义协议: 您可以定义自己的协议前缀,然后在目标URI中使用。

      uri: custom://destination

    5. 使用表达式: 您可以在routes.uri中使用SpEL表达式来动态生成目标URI。

      uri: "'http://dynamic-' + #serviceId + '.example.com'"

  • 测试路由: 启动应用程序后,您可以使用浏览器或工具(如curl或Postman)来测试配置的路由。访问http://localhost:10010/user/1应该将请求代理到http://user-service/user/1

    ![image-20230817210750025](../../../../Library/Application Support/typora-user-images/image-20230817210750025.png)

  • 添加GlobalFilter简单实现访问鉴权

    GlobalFilter是Spring Cloud Gateway中的一个重要概念,它允许您在请求和响应的生命周期中执行全局操作。这些操作可以用于各种目的,如身份验证、日志记录、添加请求头、处理异常等。GlobalFilter可以在整个网关的请求处理流程中应用,无论是在路由匹配之前还是之后。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    @Service
    public class AuthorizeFilter implements GlobalFilter, Ordered {

    @SneakyThrows(Exception.class)
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpRequest request = exchange.getRequest();
    MultiValueMap<String, String> params = request.getQueryParams();
    //获取参数中的 authorization 参数 。通常是获取header里的authorization
    String authorization = params.getFirst("authorization");
    //这里demo简单处理 判断数值是否等于 admin
    if ("admin".equals(authorization)) {
    //放行
    return chain.filter(exchange);
    }
    //先设置状态码
    ServerHttpResponse response = exchange.getResponse();
    response.setStatusCode(HttpStatus.UNAUTHORIZED);
    DataBufferFactory bufferFactory = response.bufferFactory();
    ObjectMapper objectMapper = new ObjectMapper();
    DataBuffer wrap = bufferFactory.wrap(objectMapper.writeValueAsBytes(new RestResult<>(401, "unauthrize")));
    return response.writeWith(Mono.fromSupplier(() -> wrap));
    // //拦截请求
    // return exchange.getResponse().setComplete();
    }

    //设置优先级为-1
    @Override
    public int getOrder() {
    return -1;
    }
    }

    上面代码通过对请求参数里的authorization是否等于admin简单实现了鉴权,是admin则通过

    ![image-20230817211428288](../../../../Library/Application Support/typora-user-images/image-20230817211428288.png)

    否则返回401 httpstatus和json responsebody提示

    ![image-20230817211437210](../../../../Library/Application Support/typora-user-images/image-20230817211437210.png)

集成nacos配置中心实现动态路由

  • 添加依赖:在上面配置的依赖的基础上添加nacos-config相关的依赖

    1
    2
    3
    4
    5
    <!-- nacos的配置管理依赖 -->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
  • 配置Nacos作为配置中心:bootstrap.yamlbootstrap.properties中配置Nacos的配置中心信息,包括Nacos Server的地址和配置的Data ID、Group等信息。

    bootstrap.yaml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    spring:
    application:
    name: gateway
    profiles:
    active: dev # 环境
    cloud:
    nacos:
    server-addr: localhost:8848 # nacos地址
    config:
    file-extension: yaml # 文件后缀

    application.yaml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    server:
    port: 10010
    logging:
    level:
    com.cason: debug
    spring:
    cloud:
    nacos:
    server-addr: localhost:8848
  • 配置动态路由: 在Nacos配置中心中创建配置,用于定义动态路由规则。配置的Data ID可以根据您的实际情况进行定义,我这里用的是<spring.application.name>-<spring.profiles.active>.yaml以下是一个示例配置:

    image-20230817212606004

  • 测试

    • 访问user,order相关路由没有问题

      image-20230817213157261

      image-20230817213209689

    • 移除user相关的路由,请求user相关路由404,请求order相关路由没有问题

      image-20230817213049030

      image-20230817213130551

      image-20230817213238702


API网关-SpringCloud Gateway
https://cason.work/2023/08/17/API网关-SpringCloud-Gateway/
作者
Cason Mo
发布于
2023年8月17日
许可协议