Spring Cloud 之服务网关 Gateway (一)

时间:2022-07-25
本文章向大家介绍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父项目Eureka15002注册中心Gateway15000网关Comment15003应用服务
  • 项目树 一个注册中心 一个网关 一个应用服务 |_ 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 文件配置 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 路由断言工厂类似 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 处理, 然后把请求转到后端对应的代理服务器, 处理完毕后, 将请求返回给客户端. 如果所示:

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