简介
在SpringCloud中网关作为一个重要的组成部分,网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。
API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。
所谓的APIl网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。
引出问题
1.客户端需要维护服务端的各个地址代码困难
2.认证鉴权复杂
3.跨域问题
我们开始吧
我们直接新建一个模块命名api-getaway
具体目录如下:
gateway具体是yml的配置
代码语言:txt复制server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848 #注册到nacoos
gateway:
discovery:
locator:
enabled: true #让gateway可以发现nacos中的微服务
routes: #路由数组可以放多个路由。满足什么条件转发到哪个微服务上
- id: product_route #当前路由标识,默认uuid
uri: http://localhost:8081 #要转发的地址
order: 1 #路由越小优先级越高
predicates: #断言(条件判断,返回值是bool,满足条件的)可以自定义路由配置详情看AGEROUTER
- Path=/product-serv/** #当请求的规则满足
filters: #过滤器 自定义过滤器Log
- StripPrefix=1 #在请求转发路径去掉一层
进行代码测试:我们直接访问原来的商品查询接口
是可以直接查询到的
然后我们访问我们的api网关
通过地址也是可以查询出来的,这样就是实现了我们网关的请求转发。
这样会有另一个问题,就是如果我们频繁的修改接口,那么我们就需要频繁的修改yml文件,有没有自动查找ip的呢,其实是有的,就是我们通过nacos中的服务名称进行调用,这里我们需要在pom文件引入nacos,然后在启动类中添加注册发现注解(在之前章节都有讲述,再次不做赘述)。重要的还是我们yml的配置。
代码语言:txt复制server:
port: 7000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848 #注册到nacoos
gateway:
discovery:
locator:
enabled: true #让gateway可以发现nacos中的微服务
routes: #路由数组可以放多个路由。满足什么条件转发到哪个微服务上
- id: product_route #当前路由标识,默认uuid
#uri: http://localhost:8081 #要转发的地址
uri: lb://service-product #lb负载均衡 后面是具体微服务的标识
order: 1 #路由越小优先级越高
predicates: #断言(条件判断,返回值是bool,满足条件的)可以自定义路由配置详情看AGEROUTER
- Path=/product-serv/** #当请求的规则满足
filters: #过滤器 自定义过滤器Log
- StripPrefix=1 #在请求转发路径去掉一层
# - Log=ture,false
最终要的就是这一行uri: lb://service-product ,注释已经很明确了,值得注意的就是后面的微服务名称,要与nacos的一致。
下面就是比较深入的问题,一些断言与过滤的问题了。
gateway包含很多个断言:
查看地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
基于Datetime类型的断言工厂
此类型的断言根据时间做判断,主要有三个:
AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
java可以通过ZonedDateTime.now()获取日期值
代码语言:javascript复制 ‐ After=2022-02-22T17:42:47.666-07:00[Asia/Shanghai]
基于远程地址的断言工厂
RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中
代码语言:javascript复制 ‐ RemoteAddr=192.168.1.1/24
基于Cookie的断言工厂
CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求cookie是否具有给定名称且值与正则表达式匹配。
代码语言:javascript复制‐Cookie=chocolate, ch.
基于Header的断言工厂
HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。
代码语言:javascript复制‐Header=X‐Request‐Id,d
基于Host的断言工厂
HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。
代码语言:javascript复制‐ Host=**.testhost.org
基于Method请求方法的断言工厂
MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
代码语言:javascript复制 ‐Method=GET
基于Path请求路径的断言工厂
PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。
代码语言:javascript复制‐ Path=/foo/{segment}
基于Query请求参数的断言工厂
QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。
代码语言:javascript复制 ‐Query=baz, ba.
基于路由权重的断言工厂
WeightRoutePredicateFactory:接收一个组名,权重, 然后对于同一个组内的路由按照权重转发,意思就是如果有十个请求,都是到product/*,按照1:9的转发。
代码语言:javascript复制 routes:
‐id: weight_route1
uri: host1
predicates:
‐ Path=/product/**
‐ Weight=group3, 1
‐id: weight_route2
uri: host2
predicates:
‐ Path=/product/**
‐ Weight= group3, 9
这边以上就是一些断言工厂了。
自定义断言
我们来设定一个场景:假设我们的应用仅仅让age在(min,max)之间的人来访问。
代码语言:javascript复制routes: #路由数组可以放多个路由。满足什么条件转发到哪个微服务上
- id: product_route #当前路由标识,默认uuid
#uri: http://localhost:8081 #要转发的地址
uri: lb://service-product #lb负载均衡 后面是具体微服务的标识
order: 1 #路由越小优先级越高
predicates: #断言(条件判断,返回值是bool,满足条件的)可以自定义路由配置详情看AGEROUTER
- Path=/product-serv/** #当请求的规则满足
- Age=18,60 #限制18到60的人
filters: #过滤器 自定义过滤器Log
- StripPrefix=1 #在请求转发路径去掉一层
然后新建相关类,这个类需要注意。gateway自定义;路由断言工厂前面必须- Age(可以自定义和配置yml文件一样) RoutePredicateFactory通过年龄自定义断言
年龄我们输入正确的范围内是有的,但是输入不在范围内的就会有错误的提示。
过滤器
Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么丰富,它只有两个:“pre” 和 “post”。
PRE : 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择
请求的微服务、记录调试信息等。
过滤器类型
Spring Cloud Gateway 的 Filter 从作用范围可分为另外两种GatewayFilter 与 GlobalFilter。
GatewayFilter :应用到单个路由或者一个分组的路由上。
GlobalFilter :应用到所有的路由上。
局部过滤器
局部过滤器(GatewayFilter),是针对单个路由的过滤器。可以对访问的URL过滤,进行切面处理。在
Spring Cloud Gateway中通过GatewayFilter的形式内置了很多不同类型的局部过滤器。这里简单将
Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格,虽然不是很详细,但能作为速览使
用。如下:
每个过滤器工厂都对应一个实现类,并且这些类的名称必须以 GatewayFilterFactory 结尾,这是
Spring Cloud Gateway的一个约定,例如 AddRequestHeader 对应的实现类为
AddRequestHeaderGatewayFilterFactory 。对于这些过滤器的使用方式可以参考官方文档
全局过滤器
全局过滤器(GlobalFilter)作用于所有路由,Spring Cloud Gateway 定义了Global Filter接口,用户
可以自定义实现自己的Global Filter。通过全局过滤器可以实现对权限的统一校验,安全性验证等功
能,并且全局过滤器也是程序员使用比较多的过滤器。
Spring Cloud Gateway内部也是通过一系列的内置全局过滤器对整个路由转发进行处理如下:
统一鉴权
内置的过滤器已经可以完成大部分的功能,但是对于企业开发的一些业务功能处理,还是需要我们自己
编写过滤器来实现的,那么我们一起通过代码的形式自定义一个过滤器,去完成统一的权限校验。
鉴权逻辑
开发中的鉴权逻辑:
当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
认证通过,将用户信息进行加密形成 token,返回给客户端,作为登录凭证
以后每次请求,客户端都携带认证的 token
服务端对 token进行解密,判断是否有效。
如上图,对于验证用户是否已经登录鉴权的过程可以在网关层统一检验。检验的标准就是请求中是否携
带token凭证以及token的正确性。
具体代码实现
这就是网关的基本实现了,如果更加细致的使用还是需要根据业务情况进行更改。
后期会在这个项目上不断添加,喜欢的请点个start~
项目源码参考一下分支220217_xgc_gateway
Gitee:https://gitee.com/coderxgc/springcloud-alibaba
GitHub:https://github.com/coderxgc/springcloud-alibaba