API Gateway 是微服务架构中最常用的架构模式之一,在 Spring Cloud 全家桶中也存在多种选择。除了同样出自 Netflix 的 Zuul 和它的后继者 Zuul2,还有出自自家的 Spring Cloud Gateway。
Zuul 作为一款「历史悠久」的 API Gateway 框架,经历了 Netflix 巨大流量的考验,而时间也证明了它的稳定可靠。同时 Spring Boot 提供了和它的良好集成,和其他来自于 Netflix 的框架一样,能够非常方便的与 Spring 家族的其他框架整合。
相对于 Zuul,Zuul2 可谓是一波三折,从早期宣布停止开发和闭源的传闻,到去年年中的最终发布,Zuul2 成功吸引了众多开发者的目光。在功能上 Zuul2 相比前代除了支持 http2 之外,个人觉得没有太大的提升。最吸引开发人员的是从之前的同步阻塞模型迁移到了基于 netty 的异步模型。在官方给出的评测报告中,性能大约有 20% 的提升,而在单点的连接数上也有明显的优势。美中不足的是 Spring Cloud 官方给出了明确的意见,在未来不会支持与 Zuul2 的集成。
个人觉得不再支持与 Zuul2 集成的原因是 Spring Cloud 官方有了 Zuul 的替代者,也就是今天介绍的主角 Spring Cloud Gateway。同样作为一个 API Gateway 框架,Spring Cloud Gateway 同样是基于 netty 的异步模型,因此性能上不用担心,而相同的出身也觉决定它可以很方便的和各种 Spring 框架集成,对于广大开发人员而言省却了一堆麻烦事。接下来就让我们编写一个简单的 Web 应用,体验 Spring Cloud Gateway 的强大和便捷。
依然使用 https://start.spring.io 生成项目模版,这次添加的依赖是 Spring Cloud Gateway,参考下图:
基本概念
Spring Cloud Gateway 中有些基本概念在使用前需要了解。
Route: 顾名思义就是路由,通过接受某些 Predicate,会将请求路由到下游的不同应用中去。
Predicate: 类似于 Java 8 引入的 Predicate 接口,输入参数为 Spring Framework 的 ServerWebExchange 对象,返回为布尔类型。当满足 Predicate 时,Route 就会按照路由的逻辑进行转发。
Filter: 和大家熟悉的 Java EE Filter 类似,能够拦截 http 协议的,并对输出的 http 协议内容进行修改。
在一般应用场景中我们会通过编写不同的 Predicate 将 http 请求路由到不同的下游应用中去,同时可以通过增加一系列的 filter 对 http 内容进行修改,下面就让我们看一些实际的例子。
示例工程
Spring Cloud Gateway 支持以配置文件和编程的方式对各种 route 和 filter 的逻辑进行配置。以下的示例多以配置文件为主。
先创建一个简单的 Controller,里面只有个简单的方法,会返回问候语。
@RestControllerpublic class GreetingController {@GetMapping("/morning") public String goodMorning(@RequestParam("name") final String name) {returnString.format("Good morning, %s", name); }}
接着打开 application.yaml 配置文件,增加下面的一段配置:
spring: cloud: gateway: routes: -id:greeting_routeuri: http://localhost:8080 predicates: -Path=/proxy- Query=namefilters: -RewritePath=/proxy,/morning
上面的配置很简单,且同时涉及了我之前提到的 Routes,Predicate 和 Filter 这些概念。这段配置主要的功能是,当用户访问 http://localhost:8080/proxy 时,会转发给 http://localhost:8080/morning 。同时 /proxy 的 url 需要带有 name 参数作为 url 的一部分也会传递给 /morning。完成这部分的功能分由 Routes,Predicate 和 Filter 3 部分功能完成。
Routes:我们定义了一个名为 greeting_route 的 route 组件,该 route 的功能由下属的 predicates 和 filters 元素完成。
Predicate:这部分由 2 个 Predicate 组件,即 Path 和 Query 。
Path:用以匹配传入的 url 是否满足路由转发的条件,在这里我们配置的是传入的 url 是否满足 /proxy 这一格式,如果满足,就进行后续的转发操作,Spring Cloud Gateway 是支持正则匹配,因此可以满足大部分复杂的匹配要求。
Query:要求请求的 url 参数中必须带有某个查询字符串,即 ?name=xxx 的形式,否则也不会进行转发。
Filter:默认转发的 url 是和请求的 url 一样的,在这里不符合我们要求,需要重写转发的请求,这可以通过 filter 实现。
RewritePath:Spring Cloud Gateway 提供的一个 filter 组件,可以对需要转发的 url 进行重写。在我们的配置中只是简单的将 /proxy 替换为 /morning,这部分替换的功能也是支持正则表达式的。
现在可以测试一下我们编写的第一个 API Gateway 了。启动应用后,执行下面的命令:
curlhttp://localhost:8080/proxy?name=Joshua
如果你的电脑上没有 curl 命令,可以使用 Postman发送 http 请求。此时应该返回预期的字符串:Good morning, Joshua。
更多细节
Spring Cloud Gateway 内置提供了很多现成的 Routes 和 Filter,基本能够满足日常开发的需要。下面列出了一些常用的:
After / Before / Between Route Predicate:根据请求时间在某个时间之前,之后或是之间进行转发。
Cookie Route Predicate:按照 cookie 中的数据匹配并转发。
Header Route Predicate:按照 http header 中的值匹配并转发。
RemoteAddr Route Predicate:按照 http 请求中的 remote address 进行转发。
常用的 Filters 包括:
Add RequestHeader / RequestParameter / ResponseHeader Gateway Filter:增加请求或是响应中的 header,parameter 数据。
Hystrix Gateway Filter:在 gateway 调用下游应用时启用断路器。
RequestSize Gateway Filter:对 request body 大小做限制。
Remove RequestHeader / ResponseHeader Gateway Filter:与 Add 相对,移除 Request 和 Response Header 中的数据。
原文:https://zhuanlan.zhihu.com/p/72859423
作者:白天不懂夜的黑
来源:知乎
网友评论