网关Spring Cloud Gateway科普
点击上方“朱小厮的博客”,选择“设为星标”
后台回复”加群“获取公众号专属群聊入口
欢迎跳转到本文的原文链接:https://honeypps.com/backend/introduction-of-spring-cloud-gateway/
Spring Cloud Gateway是在Spring生态系统之上构建的API网关服务,它旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能, 例如:熔断、限流、重试等。
Spring Cloud Gateway 具有如下特性:
基于Spring Framework 5、Project Reactor 和 Spring Boot 2.0 进行构建;
动态路由:能够匹配任何请求属性;
可以对路由指定 Predicate(断言)和 Filter(过滤器);
集成Hystrix的断路器功能;
集成 Spring Cloud 服务发现功能;
易于编写的 Predicate(断言)和 Filter(过滤器);
请求限流功能;
支持路径重写。
Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的 Zuul 2.0之前的非Reactor模式的老版本。(有一个版本的说法是 Zuul2.x 的连续跳票和 Zuul1.x 的性能并不是很理想,从而催生了Spring Cloud Gateway。)而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。
网上很多地方都说 Zuul 是阻塞的,Spring Cloud Gateway 是非阻塞的,这么说并不严谨的,准确的讲 Zuul1.x 是阻塞的,而在2.x的版本中,Zuul也是基于Netty,也是非阻塞的,如果一定要说性能,其实这个真没多大差距。Zuul的有关信息可以参考《网关Zuul科普》。
Spring Cloud Gateway有以下几个重要的概念,后面的内容也主要围绕这几个概念展开。
Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由;
Predicate(断言):指的是Java 8 的 Function Predicate。输入类型是Spring框架中的ServerWebExchange。这使开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数。如果请求与断言相匹配,则进行路由;
Filter(过滤器):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改。
快速入门
定义2个服务:hello-server和user-server,他们分别都注册到euraka服务上,示例如下:
在未经过网关时,我们可以通过以下2个接口来分别访问hello-server和user-server:
http://localhost:8081/hello
http://localhost:8082/user
现在我们来定义一个Spring Cloud Gateway服务,相关的Maven依赖如下:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
application.yml文件中添加如下配置:
server:port: 9091
spring:application:name: spring-cloud-gatewaycloud:gateway:routes:- id: path_route_1uri: http://localhost:8082/userpredicates:- Path=/user
各字段含义如下:
id: 我们自定义的路由ID,唯一。
uri:目标服务地址
predicates:路由条件,Predicate接受一个输入参数,返回一个布尔值结果。该接口中包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与、或、非)
这段配置的意思是:配置了一个id为 path_route_1的URI代理规则,当访问地址 http://localhost:9091/user
时,会路由到地址http://localhost:8082/user
。
Spring Cloud Gateway的路由配置和Zuul的路由配置有较大的区别,玩过Zuul的注意一下两者的区分。
启动类如下,平平无奇:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
现在我们启动Spring Cloud Gateway服务,然后请求http://localhost:9091/user:
hidden:~ hidden$ curl -i localhost:9091/user
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 11
Date: Thu, 02 Apr 2020 09:28:58 GMTUser Info!
由于没有配置过hello-server的服务,所以还不能通过网关访问它:
hidden:~ hidden$ curl -i localhost:9091/hello
HTTP/1.1 404 Not Found
Content-Type: application/json
Content-Length: 133{"timestamp":"2020-04-02T09:30:09.840+0000","path":"/hello","status":404,"error":"Not Found","message":null,"requestId":"8b0a00e1-4"}
除了使用yml配置文件的方式,还可以通过代码(Java Bean)来实现路由配置。我们在启动类中添加方法 customRouteLocator() 来定制转发规则,详情如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder builder){return builder.routes().route("path_route_2", r -> r.path("/hello").uri("http://localhost:8081/hello")).build();}
}
重启服务,再次访问hello-server的接口,可以看到访问成功:
hidden:~ hidden$ curl -i localhost:9091/hello
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 19
Date: Thu, 02 Apr 2020 09:53:25 GMTHello!
路由规则
Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。Spring Cloud Gateway 包括许多内置的 Predicate 工厂,这些 Predicate 工厂通过不同的 HTTP 请求参数来匹配,多个 Predicate 工厂可以组合使用。
Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现。
说白了 Predicate 就是为了实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理,接下来我们接下 Spring Cloud GateWay 内置几种 Predicate 的使用。
Cookie
带有指定Cookie的请求会匹配改路由。将application.yml中的spring.cloud.gateway.routes配置修改为如下内容:
spring:application:name: spring-cloud-gatewaycloud:gateway:routes:- id: cookie_routeuri: http://localhost:8082/userpredicates:- Cookie=username,pipisi
此时使用curl工具发送带有cookie为 username=pipisi 的请求就可以匹配改路由:
curl -i localhost:9091/user --cookie "username=pipisi"
Query
带指定查询参数的请求可以匹配该路由。将application.yml中的spring.cloud.gateway.routes配置修改为如下内容:
spring:application:name: spring-cloud-gatewaycloud:gateway:routes:- id: cookie_routeuri: http://localhost:8082/userpredicates:- Query=username
此时使用curl工具发送带有username=pipisi 查询参数的请求就可以匹配改路由:
curl -i localhost:9091/user?username=pipisi
其余的还有(参考上图):通过Header匹配(将predicates中的 -Query 换成 -Header,以下类同)、通过Host匹配(-Host)、通过请求方法匹配(-Method)、通过IP地址匹配(-RemoteAddr)、通过请求时间(-After、-Before、-Between)、通过权重(-Weight)以及最开始在入门示例中就提及的通过请求路径匹配(-Path)。还可以进行组合使用,比如:
predicates:- Query=username- Cookie=username,pipisi- Path=/user
各种 Predicates 同时存在于同一个路由时,请求必须同时满足所有的条件才被这个路由匹配。
过滤器
网关经常需要对路由请求进行过滤,执行一些操作,如鉴权之后构造头部之类的。过滤的种类很多,如增加请求头、增加请求参数 、增加响应头以及断路器等等,这就用到了Spring Cloud Gateway 的 过滤器(Filter)。
当我们有很多服务时,比如前面所提及的user-server和hello-server,客户端请求各个服务的API接口时,每个服务都要做相同的事情,比如鉴权、限流、日志等,如下图(上半部)。
对于这样重复的工作,可以在微服务的上一层加一个全局的权限控制、限流、日志的API网关服务,然后将请求转发到具体的业务服务层。这个API网关服务就是起到一个服务边界的作用,外界的请求访问系统,必须先通过网关层,如上图(下半部)。
Spring Cloud Gateway同 Zuul 类似,也有 pre
和 post
两种方式的过滤器:pre 过滤器在请求被路由之前调用,我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等;post 过滤器在路由到微服务以后执行,这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
Spring Cloud Gateway的 Filter生命周期如下图所示。
与 Zuul 不同的是,Filter除了分为pre
和 post
两种方式的 Filter 外,在Spring Cloud Gateway中,Filter 根据作用范围可分为另外两种,一种是针对于单个路由的 GatewayFilter,它在配置文件中的写法同 Predicate类似;另外一种是针对于所有路由的 GlobalFilter。
过滤器允许以某种方式修改传入的HTTP Request 或传出的HTTP Response,它可以限定作用在某些特定请求路径上。Spring Cloud Gateway包含了30多个内置的GatewayFilter工厂,比如AddRequestHeaderGatewayFilterFactory(添加请求头的过滤器工厂)、AddRequestParameterGatewayFilterFactory(添加请求参数的过滤器工厂)、AddResponseHeaderGatewayFilterFactory(添加响应头的过滤器工厂)、HystrixGatewayFilterFactory(Hystrix熔断过滤器工厂)、RequestRateLimiterGatewayFilterFactory(请求限流的过滤器工厂)等(全部的GatewayFilter工厂可以查看jar包中org.springframework.cloud.gateway.filter.factory目录,除了这些,你也可以自定义自己的过滤器)。
GatewayFilter工厂与前面介绍的Predicate工厂类似,都是在配置文件 application.yml 中配置,遵循了约定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名称,而不需要写全部的类名,比如 AddRequestHeaderGatewayFilterFactory 只需要在配置文件中写AddRequestHeader,而不是全部类名。官方文档都给出了这些过滤器工厂详细的使用案例,下面挑选1个案例以作演示。
案例:AddRequestHeader
application.yml配置如下:
server:port: 9091
spring:application:name: spring-cloud-gatewaycloud:gateway:routes:- id: cookie_routeuri: http://localhost:8082/userfilters:- AddRequestHeader=X-Request-Foo, Barpredicates:- Path=/user
过滤器工厂会在匹配的请求头加上一对请求头“x-request-foo=Bar”。可以在下游的user-server服务中使用@RequestHeader来查看所接收请求的请求头信息。
结合注册中心Eureka使用
Zuul 作为网关结合注册中心进行使用时,默认情况下 Zuul 会根据注册中心注册的服务列表,以服务名为路径创建动态路由,Spring Cloud Gateway同样也实现了该功能。下面我们演示下 Spring Cloud Gateway结合注册中心如何使用默认的动态路由。
首先添加Maven依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
其次修改application.yml配置文件:
server:port: 9091
spring:application:name: spring-cloud-gatewaycloud:gateway:discovery:locator:enabled: truelower-case-service-id: true
eureka:client:service-url:defaultZone: http://localhost:8761/eureka/
重启服务之后,我们就可以像 Zuul 那样采用下面的方式访问接口了:
http://localhost:9091/hello-server/hello
http://localhost:9091/user-server/user
工作原理
Spring Cloud Gateway 的核心处理流程如上图,核心逻辑就是路由转发,执行过滤器链。Gateway的客户端回向Spring Cloud Gateway发起请求,然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。在Filter链中,通过虚线分割Filter的原因是:过滤器可以在转发请求之前处理或者接收到被代理服务的返回结果之后处理。所有的Pre类型的Filter执行完毕之后,才会转发请求到被代理的服务处理。被代理的服务把所有请求完毕之后,才会执行Post类型的过滤器。
References
https://www.cnblogs.com/crazymakercircle/p/11704077.html
http://www.imooc.com/article/297943
https://www.cnblogs.com/bjlhx/p/9785926.html
https://www.jianshu.com/p/17bbc8e10545
欢迎跳转到本文的原文链接:https://honeypps.com/backend/introduction-of-spring-cloud-gateway/
想知道更多?扫描下面的二维码关注我
后台回复”加群“获取公众号专属群聊入口
【精彩推荐】
咱们从头到尾说一次Java垃圾回收
Netty、Kafka中的零拷贝技术到底有多牛?
go为什么这么快?
面试前,我们要复习多少Redis知识?
Redis性能问题分析
浅谈CAP和Paxos共识算法
聊一聊Java中的文件锁
Kafka为什么这么快?
Paxos、Raft不是一致性算法嘛?
聊聊Java的几把JVM级锁
越说越迷糊的CAP
大公司为什么都有API网关?
面试官居然问我Raft为什么会叫做Raft!
面试官给我挖坑:URI中的//有什么用
网关Zuul科普
>>> 字节跳动社招内推入口 <<<
>>> 字节跳动校招内推入口 <<<
朕已阅
网关Spring Cloud Gateway科普相关推荐
- spring boot 配置网关时404错误_网关Spring Cloud Gateway科普
Spring Cloud Gateway是在Spring生态系统之上构建的API网关服务,它旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能, 例如:熔断.限流.重试等. ...
- spring cloud gateway 网关_微服务网关Spring Cloud Gateway全搞定
一.微服务网关Spring Cloud Gateway 1.1 导引 文中内容包含:微服务网关限流10万QPS.跨域.过滤器.令牌桶算法. 在构建微服务系统中,必不可少的技术就是网关了,从早期的Zuu ...
- Spring Cloud学习笔记—网关Spring Cloud Gateway官网教程实操练习
Spring Cloud学习笔记-网关Spring Cloud Gateway官网教程实操练习 1.Spring Cloud Gateway介绍 2.在Spring Tool Suite4或者IDEA ...
- 客快物流大数据项目(一百一十七):网关 Spring Cloud Gateway
文章目录 网关 Spring Cloud Gateway 一.简介 1.功能特性
- Spring Cloud(10)——新一代网关Spring Cloud Gateway
文章目录 Spring Cloud(10)--新一代网关Spring Cloud Gateway 1.背景知识--API网关 2.Spring Cloud Gateway 详细概述 3.Spring ...
- 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析
API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...
- 网关 Spring Cloud Gateway
一. Gateway 简介 Spring Cloud Gateway 是Spring Cloud团队的一个全新项目,基于Spring 5.0.SpringBoot2.0.Project Reactor ...
- 网关Spring Cloud Gateway的配置和使用
文章目录 1. 什么是Spring Cloud Gateway? 2. Gateway与zuul的区别 3. Gateway的配置和使用 ①:常用的路由断言工厂 ②:常用的过滤器工厂(GatewayF ...
- ws配置 zuul_微服务网关 Spring Cloud Gateway
1. 为什么是Spring Cloud Gateway 一句话,Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用的还是Zuul 1.x版本,而这个版本是 ...
最新文章
- 鸿蒙os上手,Mate40 Pro鸿蒙OS快速上手体验+一点个人看法
- 关于sam9x60板卡的调试
- FSMO角色以及DC修复
- 各品牌类型电脑BOIS中USB模式启动热键
- MybatisPlus学习(四)条件构造器Wrapper方法详解
- 关于Java的File.separator
- 微软成功尝试:员工周休三天、待遇不变,工作效率却提高40%!
- mysql主从同步触发器_Mysql 主从复制触发器问题
- Python知识点-py2和py3编码
- 翻译: 如何使用 Xcode 的内存图调试器检测 iOS 内存泄漏并保留周期
- Mysql安装+卸载教程
- 华为电脑如何投屏到电视linux,华为手机如何投屏到电脑上?手把手教你,无线投屏怎么做...
- 2021 Mac系统升级后,按大小写键没反应了,切换大小写的灯不亮了
- 电脑怎么分成两个屏幕,显示不同的内容
- 如何经营好自己的朋友圈
- c语言之判断if语句
- html怎么清除背景颜色,怎么去除Word复制网页内容的背景色?
- 解决 Performing stop of activity that is not resumed 报错!!
- springboot +mybatis实现多表一对一查询
- Python2.7安装Opencv3
热门文章
- postgresql主从备份_PostgreSQL主从流复制与手动主备切换架构
- c语言进程调度报告,进程调度(C语言实现).doc
- php自定义框架,「php 框架」自定义php框架(篇一) - seo实验室
- exit()函数学习
- [NOI2018]你的名字
- MaxCompute与OSS非结构化数据读写互通(及图像处理实例)
- Python中乐高积木——函数
- CentOS 7 yum方式快速安装MongoDB
- 有没有通过代码退出程序的方法--官方解答
- 利用Scala特征(trait)的堆叠操作特性进行切面编程