Spring Cloud系列—Spring Cloud Gateway服务网关的部署与使用指南

2024-06-04 7409阅读

Gateway网关

文章目录

  • Gateway网关
      • 1. 网关基本简介
        • 1.1 什么是网关
        • 1.2 为什么需要网关?
        • 2. 快速搭建gateway网关
          • 2.1 创建新模块
          • 2.2 引入依赖
          • 2.3 编写启动类
          • 2.4 配置路由规则
          • 2.5 测试
          • 3. 路由过滤
          • 4. 过滤器
            • 4.1 简介
            • 4.2 网关过滤器
              • 4.2.2 种类
              • 4.3 自定义过滤器
                • 4.3.1 自定义GatewayFilter
                • 4.3.2 自定义GlobalFilter
                • 4.4 跨域问题
                  • 4.4.1 什么是跨域问题
                  • 4.4.2 解决跨域问题
                  • 5. 总结

                    1. 网关基本简介

                    1.1 什么是网关

                    网关,简而言之,是一个系统的单一入口点,它接收所有外部请求,并根据请求的特性(如路径、HTTP方法等)将其转发给内部的各个微服务

                    比如说,你想要向一个小区内的一个朋友送信,必须要经过看门大爷的同意,大爷如果认为好人,就会把信带给你要送的人;如果大爷认为你是坏人,就会拦截你。

                    Spring Cloud系列—Spring Cloud Gateway服务网关的部署与使用指南 第1张

                    1.2 为什么需要网关?
                    1. 路由:微服务架构通常由多个服务组成,每个服务可能部署在不同的地址和端口上。网关可以根据请求的URL或其他条件,将外部请求路由到正确的服务实例上,从而隐藏了服务实例的具体位置。
                    2. 负载均衡:当服务有多个实例时,网关可以根据不同的负载均衡策略(如轮询、随机、最少连接等)将请求分发到不同的实例,确保系统资源的有效利用和服务的稳定性。
                    3. 统一鉴权和认证:在微服务架构中,每个服务都可能有自己的安全要求。网关可以作为统一的鉴权和认证点,处理所有服务的安全验证,简化了服务之间的安全通信。
                    4. 跨域处理:由于浏览器的同源策略,前端应用在访问不同域名或端口的后端服务时可能会遇到跨域问题。网关可以配置CORS(跨源资源共享)策略,允许前端应用安全地访问后端服务。
                    5. 熔断和限流:网关可以集成熔断和限流机制,当后端服务出现问题时,网关可以快速失败,防止级联故障。同时,限流可以控制对后端服务的请求速率,防止服务过载。
                    6. 监控和日志:网关是所有外部请求的入口点,可以在这一层收集和记录重要的监控数据和日志信息,帮助开发者和运维人员快速定位问题和性能瓶颈。

                    2. 快速搭建gateway网关

                    基本步骤:

                    1. 创建新模块
                    2. 引入网关依赖
                    3. 编写启动类
                    4. 配置路由规则
                    2.1 创建新模块

                    创建一个新模块gatewawy:

                    Spring Cloud系列—Spring Cloud Gateway服务网关的部署与使用指南 第2张

                    2.2 引入依赖
                            
                            
                                org.springframework.cloud
                                spring-cloud-starter-gateway
                            
                            
                            
                                com.alibaba.cloud
                                spring-cloud-starter-alibaba-nacos-discovery
                            
                            
                            
                                org.springframework.cloud
                                spring-cloud-starter-loadbalancer
                            
                    
                    2.3 编写启动类
                    @SpringBootApplication
                    public class GatewayApplication {
                        public static void main(String[] args) {
                            SpringApplication.run(GatewayApplication.class, args);
                        }
                    }
                    
                    2.4 配置路由规则

                    gateway模块:

                    server:
                      port: 8080 
                    spring:
                      application:
                        name: gateway-service # 服务名称
                      cloud:
                        nacos:
                          server-addr: 192.168.56.101:8848 # Nacos服务注册中心的地址和端口
                        gateway:
                          routes:
                            - id: user # 路由的唯一标识符,自定义,需要保证唯一性
                              uri: lb://user-service # 路由的目标服务地址,lb表示使用负载均衡,user-service是注册中心中的服务名
                              predicates: # 路由断言,用来判断请求是否符合路由规则
                                - Path=/users/**,/addresses/** # 路由断言的路径模式,匹配以/users/或/addresses/开头的请求路径
                    

                    解析:

                    在routes部分,定义了一条路由规则,该规则将所有符合指定路径模式的请求路由到user-service服务。这条规则使用了路径断言Path,匹配所有以/users/或/addresses/开头的请求。通过使用负载均衡lb://前缀,网关能够根据注册中心中的服务实例信息进行负载均衡。

                    user-service模块:

                    server:
                      port: 8084
                    spring:
                      application:
                        name: user-service
                      cloud:
                        nacos:
                          server-addr: 192.168.56.101:8848
                    
                    2.5 测试

                    测试接口:

                    @ApiOperation("网关测试接口")
                    @GetMapping("/gateway-test")
                    public String testGateway(){
                        return "网关测试成功";
                    }
                    

                    nacos:

                    Spring Cloud系列—Spring Cloud Gateway服务网关的部署与使用指南 第3张

                    测试:

                    Spring Cloud系列—Spring Cloud Gateway服务网关的部署与使用指南 第4张

                    3. 路由过滤

                    在前面的gateway的routes部分有四个属性可以配置:

                    • id:路由的唯一标示
                    • predicates:路由断言,其实就是匹配条件
                    • filters:路由过滤条件
                    • uri:路由目标地址,lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。

                      我们在配置文件中写的断言规则只是字符串,这些字符串会被 Predicate Factory(断言工厂) 读取并处理,转变为路由判断的条件。例如 Path=/user/** 是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory 类来处理的,这里重点关注路由断言predicates:

                      名称说明示例
                      After是某个时间点后的请求- After=2037-01-20T17:42:47.789-07:00[America/Denver]
                      Before是某个时间点之前的请求- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
                      Between是某两个时间点之前的请求- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
                      Cookie请求必须包含某些cookie- Cookie=chocolate, ch.p
                      Header请求必须包含某些header- Header=X-Request-Id, \d+
                      Host请求必须是访问某个host(域名)- Host=**.somehost.org,**.anotherhost.org
                      Method请求方式必须是指定方式- Method=GET,POST
                      Path请求路径必须符合指定规则- Path=/red/{segment},/blue/**
                      Query请求参数必须包含指定参数- Query=name, Jack或者- Query=name
                      RemoteAddr请求者的ip必须是指定范围- RemoteAddr=192.168.1.1/24
                      weight权重处理

                      4. 过滤器

                      4.1 简介

                      过滤器是用于修改进入网关的请求和发出网关的响应的组件。过滤器的作用范围可以是特定的路由,也可以是全局的。过滤器可以用来添加或修改请求头和响应头,修改请求体,进行权限校验,限流,熔断等。

                      4.2 网关过滤器

                      单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,不再共享数据。也就意味着每个微服务都需要做登录校验,这显然不可取。

                      而登录校验必须在请求转发到微服务之前做,否则就失去了意义。网关的请求转发是Gateway内部代码实现的,要想在请求转发之前做登录校验,就必须了解Gateway内部工作的基本原理。

                      Spring Cloud系列—Spring Cloud Gateway服务网关的部署与使用指南 第5张

                      如图所示:

                      1. 客户端请求进入网关后由HandlerMapping对请求做判断,找到与当前请求匹配的路由规则(Route),然后将请求交给WebHandler去处理。
                      2. WebHandler则会加载当前路由下需要执行的过滤器链(Filter chain),然后按照顺序逐一执行过滤器(后面称为**Filter**)。
                      3. 图中Filter被虚线分为左右两部分,是因为Filter内部的逻辑分为pre和post两部分,分别会在请求路由到微服务之前和之后被执行。
                      4. 只有所有Filter的pre逻辑都依次顺序执行通过后,请求才会被路由到微服务。
                      5. 微服务返回结果后,再倒序执行Filter的post逻辑。
                      6. 最终把响应结果返回。

                      观察得知:如果我们能够定义一个过滤器,在其中实现登录校验逻辑,并且将过滤器执行顺序定义到NettyRoutingFilter之前,就能解决前面的问题。

                      4.2.2 种类

                      网关过滤器链中的过滤器有两种:

                      • GatewayFilter:路由过滤器,作用范围比较灵活,可以是任意指定的路由Route.
                      • GlobalFilter:全局过滤器,作用范围是所有路由,不可配置。

                        下面是一些常用的Gateway Filter和Global Filter:

                        • AddRequestHeader:添加请求头。
                        • AddResponseHeader:添加响应头。
                        • RewritePath:重写请求路径。
                        • PrefixPath:为请求路径添加前缀。
                        • SetPath:设置请求路径。
                        • Retry:设置重试逻辑。
                        • CircuitBreaker:集成熔断器。
                        • RequestRateLimiter:限流过滤器。
                        • SecureHeaders:添加安全相关的响应头。
                        • TokenRelay:用于将认证信息传递给下游服务。

                          Gateway中内置了很多的GatewayFilter,详情使用可以参考官方文档:

                          Spring Cloud Gateway

                          例如AddRequestHeaderGatewayFilterFacotry,顾明思议,就是添加请求头的过滤器,可以给请求添加一个请求头并传递到下游微服务。

                          使用的使用只需要在application.yaml中这样配置:

                          spring:
                            cloud:
                              gateway:
                                routes:
                                - id: user
                                  uri: lb://user-service
                                  predicates:
                                    -Path=/users/**
                                  filters:
                                    - AddRequestHeader=key, value # 逗号之前是请求头的key,逗号之后是value
                          

                          如果想要让过滤器作用于所有的路由,则可以这样配置:

                          spring:
                            cloud:
                              gateway:
                                default-filters: # default-filters下的过滤器可以作用于所有路由
                                  - AddRequestHeader=key, value
                                routes:
                                - id: user
                                  uri: lb://user-service
                                  predicates:
                                    -Path=/users/**
                          
                          4.3 自定义过滤器
                          4.3.1 自定义GatewayFilter
                          1. 编写过滤器工厂GatewayFilterFactory类

                          自定义GatewayFilter不是直接实现GatewayFilter,而是实现AbstractGatewayFilterFactory。最简单的方式是这样的:

                          @Component
                          public class PrintAnyGatewayFilterFactory extends AbstractGatewayFilterFactory {
                              @Override
                              public GatewayFilter apply(Object config) {
                                  return new GatewayFilter() {
                                      @Override
                                      public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                                          // 获取请求
                                          ServerHttpRequest request = exchange.getRequest();
                                          // 编写过滤器逻辑
                                          System.out.println("过滤器执行了");
                                          // 放行
                                          return chain.filter(exchange); 
                                      }
                                  };
                              }
                          }
                          

                          注意:该类的名称一定要以GatewayFilterFactory为后缀!!!

                          因为在Spring框架中,很多自动配置功能都是基于约定大于配置的原则,比如命名约定。在这里,如果你实现AbstractGatewayFilterFactory来编写类并以GatewayFilterFactory为后缀命名类的话,Spring Cloud Gateway会自动扫描并识别出那些以GatewayFilterFactory为后缀的Bean然后自动注册加载,不再需要手动配置和加载,大大简化了开发者的配置工作。如果不按照命名约定命名的话多了一步手动配置和加载。

                          1. 配置路由规则
                          spring:
                            cloud:
                              gateway:
                                default-filters:
                                      - PrintAny # 此处直接以自定义的GatewayFilterFactory类名称前缀类声明过滤器
                          

                          另外,这种过滤器还可以支持动态配置参数,不过实现起来比较复杂,示例:

                          1. 编写过滤器工厂GatewayFilterFactory类
                          @Component
                          public class PrintAnyGatewayFilterFactory // 父类泛型是内部类的Config类型
                                          extends AbstractGatewayFilterFactory {
                              @Override
                              public GatewayFilter apply(Config config) {
                                  // OrderedGatewayFilter是GatewayFilter的子类,包含两个参数:
                                  // - GatewayFilter:过滤器
                                  // - int order值:值越小,过滤器执行优先级越高
                                  return new OrderedGatewayFilter(new GatewayFilter() {
                                      @Override
                                      public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                                          // 获取config值
                                          String a = config.getA();
                                          String b = config.getB();
                                          String c = config.getC();
                                          // 编写过滤器逻辑
                                          System.out.println("a = " + a);
                                          System.out.println("b = " + b);
                                          System.out.println("c = " + c);
                                          // 放行
                                          return chain.filter(exchange);
                                      }
                                  }, 100);
                              }
                              // 自定义配置属性,成员变量名称很重要,下面会用到
                              @Data
                              static class Config{
                                  private String a;
                                  private String b;
                                  private String c;
                              }
                              // 将变量名称依次返回,顺序很重要,将来读取参数时需要按顺序获取
                              @Override
                              public List shortcutFieldOrder() {
                                  return List.of("a", "b", "c");
                              }
                                  // 返回当前配置类的类型,也就是内部的Config
                              @Override
                              public Class getConfigClass() {
                                  return Config.class;
                              }
                          }
                          
                          1. 配置路由规则
                          spring:
                            cloud:
                              gateway:
                                default-filters:
                                      - name: PrintAny # 自定义过滤器的名称
                                        args: # 过滤器传递的参数,手动指定参数名,无需按照参数顺序
                                          a: 1
                                          b: 2
                                          c: 3
                          
                          4.3.2 自定义GlobalFilter

                          自定义GlobalFilter则简单很多,直接实现GlobalFilter即可,而且也无法设置动态参数:

                          @Component
                          public class PrintAnyGlobalFilter implements GlobalFilter, Ordered {
                              @Override
                              public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                                  // 编写过滤器逻辑
                                  System.out.println("未登录,无法访问");
                                  // 放行
                                  // return chain.filter(exchange);
                                  // 拦截
                                  ServerHttpResponse response = exchange.getResponse();
                                  response.setRawStatusCode(401);
                                  return response.setComplete();
                              }
                              @Override
                              public int getOrder() {
                                  // 过滤器执行顺序,值越小,优先级越高
                                  return 0;
                              }
                          }
                          
                          4.4 跨域问题
                          4.4.1 什么是跨域问题

                          跨域问题(Cross-Origin Resource Sharing, CORS)是指由于浏览器的同源策略(Same-Origin Policy)限制,一个源(域名、协议和端口)的网页无法向另一个源发送HTTP请求的问题。同源策略是一种安全机制,旨在防止恶意网站访问敏感数据。

                          同源的定义是:如果两个页面的协议、域名(或IP地址)和端口都相同,则它们具有相同的源。例如,以下两个URL具有相同的源:

                          • http://example.com:80/index.html
                          • http://example.com:80/page.html

                            而以下URL与上面的URL不同源:

                            • https://example.com:80/index.html (协议不同)
                            • http://www.example.com:80/index.html (域名不同)
                            • http://example.com:81/index.html (端口不同)

                              当尝试从不同源的客户端发送请求到服务器时,浏览器会阻止这些请求,除非服务器明确允许跨源请求。这就是所谓的跨域问题。

                              4.4.2 解决跨域问题

                              全局CORS配置:在网关的配置文件中,可以定义全局的CORS配置,这些配置会应用到所有的路由上。

                              spring:
                                application:
                                  name: gateway
                                cloud:
                                  nacos:
                                    server-addr: 192.168.56.101:8848
                                  gateway:
                                    globalcors:
                                      add-to-simple-url-handler-mapping: true # 因为ajax发起者会通过options请求来向服务器询问是否允许跨域,所以需要设置为true来解决options请求被拦截问题
                                      corsConfigurations:
                                        '[/**]':
                                          allowedOrigins: "http://www.xxx.com" # 允许那些网站跨域访问
                                          allowedMethods: # 允许的HTTP方法
                                            - GET
                                            - POST
                                            - PUT
                                            - DELETE
                                          allowedHeaders: "*" # 允许的请求头
                                          allowCredentials: true # 是否允许发送Cookie
                                          maxAge: 3600 # 预检请求的缓存时间(秒)
                              

                              5. 总结

                              本文深入探讨了Spring Cloud Gateway网关的核心概念及其在微服务架构中的快速部署方法,除此之外着重讲解了Gateway过滤器(Filters)的重要性以及相关使用,包括过滤器的种类、自定义过滤器的实现以及过滤器在解决跨域问题中的作用。

                              至于具体的应用要根据实际开发要求编写,这里就不过多展示了,希望对大家有所帮助。


                              参考资料:

                              Gateway网关 - wenxuehai - 博客园 (cnblogs.com)

                              gateway Strict-origin-when-cross-origin跨域问题解决 | 少将全栈 (whatled.com)

                              微服务02


    免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

    目录[+]