服务网关:Spring Cloud Gateway
API 网关
API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
- 客户端会多次请求不同的微服务,增加了客户端的复杂性。
- 存在跨域请求,在一定场景下处理相对复杂。
- 认证复杂,每个服务都需要独立认证。
- 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
- 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。
以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性,典型的架构图如图所示:
使用 API 网关后的优点如下:
- 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
- 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
- 减少了客户端与各个微服务之间的交互次数。
Spring Cloud Gateway 简介
Spring Cloud Gateway 是 Spring Cloud 团队的一个全新项目,基于 Spring 5.0、SpringBoot2.0、Project Reactor 等技术开发的网关。 旨在为微服务架构提供一种简单有效统一的 API 路由管理方式。
Spring Cloud Gateway 作为 SpringCloud 生态系统中的网关,目标是替代 Netflix Zuul。Gateway 不仅提供统一路由方式,并且基于 Filter 链的方式提供网关的基本功能。例如:安全,监控/指标,和限流。
Spring Cloud Gateway 本身也是一个微服务,需要注册到 Eureka
网关的核心功能:过滤、路由
核心概念:
- 路由(route):
- 断言 Predicate 函数:路由转发规则
- 过滤器(Filter):
快速入门
1、创建工程
创建一个子工程 gateway-service
1 | <dependencies> |
创建启动类com.atguigu.GatewayApplication
1 |
|
2、基础配置
application.yml
配置
1 | # 注释版本 |
3、路由配置
通过网关配置一个路由功能,用户访问网关的时候,如果用户请求的路径是以/user
开始,则路由到user-provider
服务去
修改 application.yml 配置即可实现,配置如下:
1 | # 注释版本 |
概念解释:
Route(路由)
:路由是网关的基本单元,由 ID、URI、一组 Predicate、一组 Filter 组成,根据 Predicate 进行匹配转发。Predicate(谓语、断言)
:路由转发的判断条件Filter(过滤器)
:过滤器是路由转发请求时所经过的过滤逻辑,可用于修改请求、响应内容。
4、测试
启动 GatewayApplication 测试
浏览器访问:http://localhost:18084/user/find/2
会访问user-provider
服务,效果如下:
5、动态路由
刚才路由规则中,我们把路由的服务地址写死了。
如果服务提供者集群的话,这样做不合理。应该是根据服务名称,去 Eureka 注册中心查找服务对应的所有实例列表,然后进行动态路由。
修改 application.yml,修改映射配置:通过服务名称获取:
1 | spring: |
路由配置中 uri 所用的协议为 lb 时,gateway 将把 user-provider 解析为实际的主机和端口,并通过 Ribbon 进行负载均衡。
浏览器访问:http://localhost:18084/user/find/2
6、过滤器
过滤器作为 Gateway 的重要功能。常用于请求鉴权、服务调用时长统计、修改请求或响应 header、限流、去除路径等。
① 过滤器的分类
- 默认过滤器:出厂自带,实现好了拿来就用,不需要实现
- 全局默认过滤器
- 局部默认过滤器
- 自定义过滤器:根据需求自己实现,实现后需配置,然后才能使用
- 全局过滤器:作用在所有路由上
- 局部过滤器:配置在具体路由下,只作用在当前路由上
默认过滤器几个,常见如下:
过滤器名称 | 说明 |
---|---|
AddRequestHeader | 对匹配上的请求加上 Header |
AddRequestParameters | 对匹配上的请求路由 |
AddResponseHeader | 对从网关返回的响应添加 Header |
StripPrefix | 对匹配上的请求路径去除前缀 |
详细说明:官方文档
② 默认过滤器配置
默认过滤器有两个:全局默认过滤器和局部默认过滤器。
[1]全局过滤器
对输出响应头设置属性
对输出的响应设置其头部属性名称为 X-Response-Default-MyName,值为 atguigu
修改 gateway-service
的 yml
配置文件
1 | spring: |
浏览器访问:http://localhost:18084/user/find/2
查看浏览器响应头信息
[2]局部过滤器配置
通过局部默认过滤器,修改请求路径。局部过滤器在这里介绍两种:添加路径前缀、去除路径前缀。
(1)添加路径前缀
在 gateway 中可以通过配置路由的过滤器 PrefixPath 实现映射路径中的前缀
配置请求地址添加路径前缀过滤器
路由地址信息:
配置 | 访问地址 | 路由地址 |
---|---|---|
PrefixPath=/user | http://localhost:18084/find/2 | http://localhost:18081/user/find/2 |
浏览器请求:http://localhost:18084/find/2
时路由器会自动添加/user
全局和局部的区别:全局是对所有的 id 有效,局部只是对某一个 id 有效
(2)去除路径前缀
在 gateway 中通过配置路由过滤器 StripPrefix,实现映射路径中地址的去除。通过 StripPrefix=1 来指定路由要去掉的前缀个数。
如:路径/api/user/1 将会被路由到/user/1。
http://localhost:18084/api/user/2
可以去掉指定个数的前缀 http://localhost:18084/user/2
配置去除路径前缀过滤器
1 | spring: |
浏览器访问:http://localhost:18084/api/user/2
路由地址信息:
配置 | 访问地址 | 路由地址 |
---|---|---|
StripPrefix=1 | http://localhost:18084/api/user/find/2 | http://localhost:18081/user/find/2 |
StripPrefix=2 | http://localhost:18084/api/hello/user/find/2 | http://localhost:18081/user/find/2 |
③ 自定义过滤器配置
[1]全局自定义过滤器
自定义全局过滤器的案例:模拟登陆校验。
基本逻辑:如果请求中有 Token 参数,则认为请求有效放行,如果没有则拦截提示授权无效
在gateway-service
中创建com.atguigu.filter.LoginGlobalFilter
全局过滤器类
1 |
|
测试:
不携带 token:http://localhost:18084/hahah/user/find/2
携带 token:http://localhost:18084/hahah/user/find/2?token=1
[2]局部过滤器定义
自定义局部过滤器,该过滤器在控制台输出配置文件中指定名称的请求参数及参数的值
局部过滤器作用范围:该局部过滤器在哪个 id 下配置,则该局部过滤器只针对该 id 的路由规则有效
比如这里就是只针对id
为user-service-route
的路由规则有效。
约定过滤器的前缀为配置的 name,而后面都是GatewayFilterFactory
命名需要以 GatewayFilterFactory 结尾,比如 MyParamGatewayFilterFactory ,那么在使用的时候 MyParam 就是这个过滤器工厂的名称
在gateway_service
中编写MyParamGatewayFilterFactory
类
1 |
|
修改 application.yml 配置文件