Spring Cloud 之服务网关 Gateway (一)

Spring Cloud 之服务网关 Gateway

概述

Spring Cloud Gateway 是Spring官方基于 Spring 5.0, Spring Boot 2.0 和 Project Reactor 等技术开发的网关,Spring Cloud Gateway 旨在为微服务架构提供一种简单而有效的统一的API路由管理方式. Spring Cloud Gateway作为Spring Cloud生态系中的网关. 目标是替代 Netflix ZUUL, 其不仅提供统一的路由方式, 并且基于 Filter 链的方式提供了网关基本的功能, 例如: 安全, 监控/埋点, 和限流等

与 zuul 的区别

spring-cloud-gateway 是 spring-cloud 的一个子项目. 而 zuul 则是 netflix 公司的项目, 只是 spring 将 zuul 集成在 spring-cloud 中使用而已. 因为 zuul2.0 连续跳票和 zuul1 的性能表现不是很理想. 所以催生了 spring 团队开发了 Gateway 项目. 简单来说, gateway 是spring-cloud的亲儿子, zuul 别人家的孩子. 所以总整体性能和与spring cloud 兼容程度来说, gateway 优于 zuul

简单案例实现一个网关(Java 代码)

聚合模块说明

  • 版本说明

    Spring Boot : 2.0.9.RELEASE

    Spring Cloud: Finchley.RELEASE

  • 项目整体结构采用 maven 多 Module 结构

    模块 端口 说明
    Demo 父项目
    Eureka 15002 注册中心
    Gateway 15000 网关
    Comment 15003 应用服务
  • 项目树

    一个注册中心
    一个网关
    一个应用服务
    |_ demo
    	|_ eureka
    	|_ gateway
    	|_ comment
    	|_ pom.xml
    

编写 Eureka 服务

参考: Spring Cloud 之 Eureka 服务注册与发现

编写 Gateway 网关服务

  • 编写 pom 文件

    在 gateway 里引入 Spring Retry 的 jar 包

    <dependencies>
        <!-- 健康监控 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- Spring Cloud Gateway 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    
  • application.yml 文件配置

    扫描二维码关注公众号,回复: 11721011 查看本文章
    spring:
      application:
        name: gateway
      cloud:
        gateway:
          discovery:
            locator:
              enabled: true     # 开启基于服务发现的路由规则
              lower-case-service-id: true   # 开启小写的 serviceId 进行基于服务路由的转发
          routes:
          # 路由集群内其他服务,url 需要用 [lb://]+[serviceId](lb:loadbalance)
            - id: comment-server
              uri: lb://comment-server
              predicates:
                 - Path=/comment-server
        loadbalancer:
          retry:
            enabled: true # 内部已默认开启负载均衡
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:15002/eureka/  # 指定注册中心地址, 以便使用服务发现功能
      instance:
        lease-renewal-interval-in-seconds: 5
        lease-expiration-duration-in-seconds: 15
        perfer-in-address: true
    
    server:
      port: 15000
    
    management:
      endpoints:
        health:
          enabled: true
        gateway:
          enabled: true
        web:
          exposure:
            include: "*" # 暴露所有端点, 默认是 info, health
    
    logging:
      level:
        org.springframework.cloud.gateway: debug
    
  • 启动类

    @SpringBootApplication
    public class GatewayApplication {
          
          
        public static void main(String[] args) {
          
          
            SpringApplication.run(GatewayApplication.class, args);
        }
    }
    

​ 网关启动后, 由于开启了健康检查, 可以通过访问: http://localhost:15000/actuator/gateway/routes 查看路由 配置信息

编写应用程序服务 comment-server

  • 编写 pom 文件

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    
  • 编写工程的配置文件,

    eureka:
      client:
        serverUrl:
          defaultZone: http://localhost:15002/eureka/
      instance:
        lease-renewal-interval-in-seconds: 5
        lease-expiration-duration-in-seconds: 15
        perfer-in-address: true
    
    server:
      port: 15003
    
    spring:
      application:
        name: comment-server
    
  • 编写控制器

    @RestController
    @RequestMapping("/comments")
    @Slf4j
    public class CommentController {
          
          
        @GetMapping("/{id}")
        public String getJokes(@PathVariable("id") String id) {
          
          
            log.debug("Get comments");
            return id;
        }
    }
    

发送请求测试效果

注册中心(eureka), 网关服务(gateway) 和应用服务(comment-server)依次启动后, 访问 http://localhost:15000/comment-server/comments/123 返回 123, 说明通过访问网关的 15000 接口, 成功路由到 应用服务并返回结果.

路由转发配置

Path 路由断言工厂

Path 路由断言工厂根据请求的路径进行路由匹配. 值得注意的是, 如果路由集群内其他服务,url 需要用 [lb://]+serviceId

routes:
  # 路由集群内其他服务,url 需要用 [lb://]+[serviceId](lb:loadbalance)
  - id: path_route
    uri: lb://comment-server
    predicates:
    - Path=/comment-server

访问 http://localhost:15000/comment-server/comments/123 返回 123, 说明通过访问网关的 15000 接口, 成功路由到 应用服务并返回结果.

Host 路由断言工厂

Host 路由断言工厂根据配置的 Host,对请求中的 Host 进行断言处理(配置主机名的时候, 如果gateway是80端口, 则可以省略. 如果是别的端口号, 需要在断言后面加上对应的端口阿红 eg: Host=****.csdn.****:15000)

routes:
	# Host 路由断言工厂
	- id: host_route
	  uri: https://blog.csdn.net/zjhcxdj/category_9771365.html
	  predicates:
	    - Host=**.csdn.**:15000 # 请求域名中携带 csdn,则转发

本地hosts文件配置:

127.0.0.1 vip.csdn.com

访问: http://vip.csdn.com:15000/ 跳转到 https://blog.csdn.net/zjhcxdj/category_9771365.html

Query 路由断言工厂

Query 路由断言工厂会从请求中获取请求的参数及其参数值, 然后与 Query断言路由中的配置进行匹配

routes:
	- id: query_route
	  uri: https://blog.csdn.net/zjhcxdj/article/details/106992956
	  predicates:
	    - Query=username,zzz # 请求参数含有username,且值为zzz

访问: http://localhost:15000/?username=zzz 跳转到 https://blog.csdn.net/zjhcxdj/article/details/106992956

Header 路由断言工厂

Header 路由断言工厂类似 Query 路由断言方式, 只不过是从请求的 header 里取一个参数及参数值. 用于根据配置的路由 header 信息进行断言匹配路由

routes:
     - id: header_route
       uri: https://blog.csdn.net/zjhcxdj/article/details/105631321
       predicates:
       - Header=request, \d+ # 如果请求头含有request,且为数字,则转发

通过 postman 访问 http://localhost:15000 并在 header 里设置 request:121231, 则会返回 https://blog.csdn.net/zjhcxdj/article/details/105631321 的页面内容

Cookie 路由断言工厂

Cookie 路由断言工厂类似 Query 路由断言方式, 只不过是从请求的 Cookie 里取一个参数及参数值. 用于根据配置的路由 header 信息进行断言匹配路由

routes:
	- id: cookie_route
      uri: https://blog.csdn.net/zjhcxdj/article/details/105631321
      predicates:
        - Cookie=name, zzzgd # 如果携带cookie,参数名为name,值为zzzgd,则转发

Gateway 工作原理

客户端向 Gateway 发起请求, 请求首先会被 HttpWebHandlerAdapter 进行提取组装成网关的上下文, 然后网关的上下文会传递到 DispatcherHandler . DispatcherHandler 是所有请求的分发处理器, 主要负责请求对应的处理器. 比如将请求分发到对应的 RoutePredicateHandlerMapping (路由断言处理映射器). 路由断言处理映射器主要用于路由的查找, 以及找到路由后返回对应的 FilteringWebHandler. FilteringWebHandler 主要负责组装 Filter 链表并调用 Filter 执行一系列的 Filter 处理, 然后把请求转到后端对应的代理服务器, 处理完毕后, 将请求返回给客户端. 如果所示:

gateway工作原理

(在 Filter 链中, 通过虚线分割 Filter 的原因是, Filter 可以在转发请求之前处理或者接受到被代理的服务返回结果之后处理. 所有的 Pre 类型的 Filter 执行完毕后, 才会转发到被代理的的服务处理. 被代理的服务把所有的请求处理完毕后, 才会执行 Post 类型的服务器)

猜你喜欢

转载自blog.csdn.net/zjhcxdj/article/details/108596906