【SpringCloud技术专题】「Gateway网关系列」(2)微服务网关服务的Gateway功能配置指南分析

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 【SpringCloud技术专题】「Gateway网关系列」(2)微服务网关服务的Gateway功能配置指南分析

Spring Cloud Gateway简介


  • Spring Cloud Gateway是Spring Cloud体系的第二代网关组件,基于Spring 5.0的新特性WebFlux进行开发,底层网络通信框架使用的是Netty,所以其吞吐量高、性能强劲,未来将会取代第一代的网关组件Zuul。


  • Spring Cloud Gateway可以通过服务发现组件自动转发请求,默认集成了Ribbon做负载均衡,以及默认使用Hystrix对网关进行保护,当然也可以选择其他的容错组件,例如Sentinel。



SpringCloud Gateway优点


  • 性能强劲:是第一代网关Zuul的1.6倍
  • 功能强大:内置了很多实用的功能,例如转发、监控、限流等
  • 设计优雅,容易扩展


SpringCloud Gateway缺点


  • 学习复杂度:其实现依赖Netty与WebFlux,不是传统的Servlet编程模型,有一定的学习成本
  • 部署特殊性:不能在Servlet容器下工作,也不能构建成WAR包,即不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行,不支持Spring Boot 1.x,需2.0及更高的版本



核心概念


Route(路由)


Spring Cloud Gateway的基础元素,可简单理解成一条转发规则。包含:路由ID、目标URL、Predicate集合以及Filter集合。


Gateway路由配置案例:
spring:
  cloud:
    gateway:
      routes:
      - id: server-center  # 唯一标识,通常使用服务id
        uri: lb://server-center  # 目标URL,lb代表从注册中心获取服务,lb是Load Balance的缩写
        predicates:   # Predicate集合
          - Path=/sample/cloud/v1/server-center/**  # 匹配转发路径
        # Filter集合
        filters:
        # 从第几级开始转发
          - StripPrefix=4
复制代码


Predicate(谓词)

即java.util.function.Predicate这个接口,Gateway使用Predicate实现路由的匹配条件



Filter(过滤器)

与我们平时使用的Servlet编程模型里的过滤器概念类似,同样可以用于修改请求以及响应数据,可以利用Filter实现鉴权、访问日志记录,接口耗时记录等功能


Spring Cloud Gateway架构图

image.png

流程介绍:


Gateway Client发送请求给Spring Cloud Gateway,Gateway Handler Mapping会判断请求的路径是否匹配路由的配置,如果匹配则会进入Gateway Web Handler,Web Handler会读取路由上所配置的过滤器,然后将该请求交给过滤器去处理,最后转发到路由配置的微服务上。


  • Gateway Client:泛指外部请求,例如浏览器、app、小程序等
  • Proxied Service:指的是被网关代理的微服务



相关源码:


Gateway Handler Mapping:org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping
Gateway Web Handler:org.springframework.cloud.gateway.handler.FilteringWebHandler

实际开发案例


创建Spring Cloud Gateway项目


这里使用IDEA的Spring Initializr进行项目的创建,到选择依赖这一步勾选gateway依赖,如下图:

image.png

网关组件一般都配合服务发现组件使用,我这里使用Nacos作为服务发现组件,具体的依赖如下(2.1.x为例):

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- Nacos Client -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!-- actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <!--整合Spring Cloud-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--整合Spring Cloud Alibaba-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.1.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
复制代码



然后编写配置文件内容如下:

server:
  port: 8040
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        # 指定nacos server的地址
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          # gateway通过服务发现组件找到其他的微服务,从而自动转发请求
          enabled: true
# actuator相关配置
management:
  endpoints:
    web:
      exposure:
        # 暴露所有监控端点
        include: '*'
  endpoint:
    health:
      # 总是显示健康检测详情
      show-details: always
复制代码

完成以上步骤后,我们来启动这个网关服务,进行一个简单的测试,看看是否能将请求正常地转发到指定的微服务上。


此时有一个名为server-center的微服务,该微服务有一个按id获取用户信息的接口,接口路径为/users/{id}。


若通过网关服务来访问这个接口,要如何做呢?很简单,gateway配合服务发现组件使用时,会有一个默认的转发规则,如下:

${GATEWAY_URL}/{微服务名称}/{接口路径}
复制代码

按该规则得出来的具体url为:localhost:port/server-center/users/{id},gateway可以根据url上的微服务名称将访问请求转发到该微服务上。



自定义路由的注意事项:


predicates配置项必须有,且必须配置一个及以上的Predicate,但不一定非要配置Path,可以配置其他的Predicate,例如After、Before等,此时Path的默认值为/**


路由配置的两种形式


Spring Cloud Gateway的路由配置有两种形式,分别是路由到指定的URL以及路由到指定的微服务。

在这两种形式中,均支持访问路径的通配及精确匹配,在之前的示例中我们只使用了通配。这里将给出具体的配置示例,以此直观的了解这两种形式及不同匹配方式在配置上的区别。


路由到指定的URL


通配,使用通配符/**进行匹配,示例:


spring:
  cloud:
    gateway:
      routes:
        - id: test_route  # 路由的唯一标识
          uri: http://www.xxx.com
          predicates:
            # 使用通配符匹配
            - Path=/**
复制代码


该配置使访问 GATEWAY_URL/** 时会转发到 www.xxx.com/



精确匹配


配置具体的接口路径即可,示例:

spring:
  cloud:
    gateway:
      routes:
        - id: test_route  # 路由的唯一标识
          uri: http://www.xxx.com/user/order/detail
          predicates:
            # 指定具体的路径进行匹配
            - Path=/user/order/detail
复制代码

该配置使访问 GATEWAY_URL/user/order/detail 时会转发到 ttp://www.xxx.com/user/order/…


路由到指定的微服务


通配,示例:

spring:
  cloud:
    gateway:
      routes:
        - id: server-center  # 路由唯一标识,这种形式下通常是微服务名称
          uri: lb://server-center  # lb代表从注册中心获取服务
          predicates:
            # 使用通配符匹配
            - Path=/**
复制代码

该配置使访问 GATEWAY_URL/** 时会转发到 server-center微服务的/** 精确匹配,示例:

spring:
  cloud:
    gateway:
      routes:
        - id: server-center  # 路由的唯一标识,这种形式下通常是微服务名称
          uri: lb://server-center/users/info  # lb代表从注册中心获取服务
          predicates:
            # 指定具体的路径进行匹配
            - Path=/users/info
复制代码

该配置使访问 GATEWAY_URL/users/info 时会转发到 server-center微服务的/users/info。



路由谓词工厂


前面提到过谓词是路由的判断条件,而路由谓词工厂就是作用到指定路由上的一堆谓词判断条件。在之前的示例里,我们就已经使用过路由谓词工厂了,就是自定义转发路径时所配置的Path。



内置的路由谓词工厂


Spring Cloud Gateway内置了众多路由谓词工厂,这些路由谓词工厂为路由匹配的判断提供了有力的支持,而我们之前所使用的Path就是内置的路由谓词工厂之一,用于判断当前访问的接口路径是否与该路由所配置的路径相匹配,若匹配则进行转发。


由于Gateway内置的路由谓词工厂比较多,篇幅有限就不在本文中介绍了,可以参考另一篇文章:


自定义路由谓词工厂


Spring Cloud Gateway内置了一系列的路由谓词工厂,但如果这些内置的路由谓词工厂不能满足业务需求的话,我们可以自定义路由谓词工厂来实现特定的需求。


例如有某个服务限制用户只允许在09:00 - 17:00这个时间段内才可以访问,内置的路由谓词工厂是无法满足这个需求的,所以此时我们就需要自定义能够实现该需求的路由谓词工厂。


首先定义一个配置类,用于承载时间段的配置参数:


@Data
public class TimeBetweenConfig {
    /**
     * 开始时间
     */
    private LocalTime start;
    /**
     * 结束时间
     */
    private LocalTime end;
}
复制代码



然后定义一个路由谓词工厂,具体代码如下:

/**
 * 路由谓词工厂必须以RoutePredicateFactory结尾,
 * 这是Spring Cloud Gateway的约定
 **/
@Slf4j
@Component
public class TimeBetweenRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenConfig> {
    public TimeBetweenRoutePredicateFactory() {
        super(TimeBetweenConfig.class);
    }
    /**
     * 实现谓词判断的方法
     */
    @Override
    public Predicate<ServerWebExchange> apply(TimeBetweenConfig config) {
        return exchange -> {
            LocalTime start = config.getStart();
            LocalTime end = config.getEnd();
            // 判断当前时间是否为允许访问的时间段内
            LocalTime now = LocalTime.now();
            return now.isAfter(start) && now.isBefore(end);
        };
    }
    /**
     * 控制配置类(TimeBetweenConfig)属性和配置文件中配置项(TimeBetween)的映射关系
     */
    @Override
    public List<String> shortcutFieldOrder() {
        /*
         * 例如我们的配置项是:TimeBetween=上午9:00, 下午5:00
         * 那么按照顺序,start对应的是上午9:00;end对应的是下午5:00
         **/
        return Arrays.asList("start", "end");
    }
}
复制代码



最后需要在配置文件中启用该路由谓词工厂,并且需要禁止gateway通过服务发现组件转发请求到其他的微服务,修改Gateway相关配置如下:

spring:
  cloud:
    gateway:
      discovery:
        locator:
          # 禁止gateway通过服务发现组件转发请求到其他的微服务
          enabled: false
      routes:
        - id: server-center
          # 目标URL,lb代表从注册中心获取服务
          uri: lb://server-center
          predicates:
            # 注意名称必须为路由谓词工厂类名的前缀,参数为允许访问的时间段
            - TimeBetween=上午9:00,下午5:00
复制代码



可以看到这里主要是配置了我们自定义的路由谓词工厂类名的前缀以及允许访问的时间段,这个时间格式不是随便配置的,而是Spring Cloud Gateway的默认时间格式,相关源码如下:

org.springframework.format.support.DefaultFormattingConversionService#addDefaultFormatters
复制代码



时间格式是可以注册的,关于时间格式注册的相关源码如下:

org.springframework.format.datetime.standard.DateTimeFormatterRegistrar#registerFormatters
复制代码



  • 这里之所以要禁止gateway通过服务发现组件转发请求到其他的微服务,是因为开启该配置项的话会导致我们自定义的路由谓词工厂不生效。


  • 不生效也是有原因的,开启该配置项会令Gateway优先将请求按照该配置项进行转发,那么我们自定义的路由就不会生效。


www.jianshu.com/p/97bf2aa1b…

blog.51cto.com/zero01/2430…

www.jianshu.com/p/1436a94ec…

blog.csdn.net/qq_38380025…

www.jianshu.com/p/66d664787…

www.jianshu.com/p/0813d35ae…




相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
28天前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
52 2
|
7天前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
36 3
|
15天前
|
运维 NoSQL Java
后端架构演进:微服务架构的优缺点与实战案例分析
【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
55 4
|
1月前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
28天前
|
JSON Java 数据格式
【微服务】SpringCloud之Feign远程调用
本文介绍了使用Feign作为HTTP客户端替代RestTemplate进行远程调用的优势及具体使用方法。Feign通过声明式接口简化了HTTP请求的发送,提高了代码的可读性和维护性。文章详细描述了Feign的搭建步骤,包括引入依赖、添加注解、编写FeignClient接口和调用代码,并提供了自定义配置的示例,如修改日志级别等。
75 1
|
1月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
4月前
|
监控 负载均衡 Java
深入理解Spring Cloud中的服务网关
深入理解Spring Cloud中的服务网关
|
1月前
|
安全 5G 网络性能优化
|
2月前
|
监控 负载均衡 安全
微服务(五)-服务网关zuul(一)
微服务(五)-服务网关zuul(一)
|
3月前
|
运维 Kubernetes 安全
利用服务网格实现全链路mTLS(一):在入口网关上提供mTLS服务
阿里云服务网格(Service Mesh,简称ASM)提供了一个全托管式的服务网格平台,兼容Istio开源服务网格,用于简化服务治理,包括流量管理和拆分、安全认证及网格可观测性,有效减轻开发运维负担。ASM支持通过mTLS提供服务,要求客户端提供证书以增强安全性。本文介绍如何在ASM入口网关上配置mTLS服务并通过授权策略实现特定用户的访问限制。首先需部署ASM实例和ACK集群,并开启sidecar自动注入。接着,在集群中部署入口网关和httpbin应用,并生成mTLS通信所需的根证书、服务器证书及客户端证书。最后,配置网关上的mTLS监听并设置授权策略,以限制特定客户端对特定路径的访问。
130 2