我们用网关做了这些事情:
- 1.实现路由功能;
- 2.整合Swagger API文档;
- 3.文件URI的全局修改;
- 4.统一校验Token;
- 5.统一校验资源访问权限;
- 6.对外开放API统一签名校验。
实现路由功能
实现路由功能的目的是统一流量入口,为前端屏蔽后端多个微服务的存在,无需为后端每个微服务都通过域名将接口暴露于外网。
之前我们项目是通过nginx实现请求路由功能,但我们需要的不仅仅是路由功能,路由功能只是网关的最基础功能。
整合Swagger API文档
项目微服务化后接口文档也随之分散,前期由于我们是使用nginx做路由,配置swagger路由又太过麻烦,前端同事也需要记住路由规则,因此我们放弃通过配置路由访问接口文档。
在没有网关之前,前端同事无法访问测试环境的接口文档,我们只能在本地启动微服务让前端同事通过局域网访问API接口文档。
引入网关后我们希望能统一API文档入口。详细的整合步骤笔者已单独整理出一篇教程《在网关实现合并多个微服务Swagger接口文档的详细步骤》,最终实现的效果如下图所示。
文件URI的全局修改
由于域名、路由前缀都有修改的可能,一般图片上传后我们只存储图片的相对路径到数据库,但响应给前端的必须是完整的url,否则图片无法访问,因此我们必须要在响应前为所有图片url拼接上域名与路由。
以修改用户头像为例,前端需要先调用文件上传接口上传图片并获取到图片上传后的url,再携带图片url调用修改用户头像的接口。由于前端可能需要实现上传后回显,因此文件上传接口响应的图片url也必须是完整的,这样就导致前端调用修改用户头像接口传的图片url也是完整的,我们不得不在修改用户头像的接口实现去掉头像url的域名和路由。
一个接口可以这样,很多个接口呢?如果不怕麻烦,那确实每个接口都可以这样写。
对于这类重复性操作,我们选择将其移至网关统一实现,并且当路由、域名修改后其它微服务也不需要做任何的改动。
想要实现为图片url去掉或拼接域名与路由并不难,难的是我们如何从请求body以及从响应body中识别出哪些字段是文件url。
首先是如何从请求body识别出哪个字段传的是文件url。由于前端传的文件url是完整的,因此可根据域名、路由和文件名后缀使用正则匹配替换。域名、路由、文件名后缀这三个条件缺一不可。匹配域名和路由是避免匹配到第三方网站的图片链接或是以前上传的图片(向后兼容),匹配文件名后缀是确保这是一个文件链接,而不是接口链接。
其次是如何从响应body识别出哪个字段传的是文件链接。我们只能通过后缀名去匹配,当匹配上后缀名后还需要判断链接是否已经是完整的链接,对于完整的链接就无需做拼接。
在实现过程中需要注意的地方:当我们修改请求或响应body时,其长度可能会发生变化,因此必须要记得修改请求或响应头的ContentLength。
如果是基于Spring Cloud Gateway实现的网关,由于是异步响应式的,对于请求数据包,先是请求头被写入InputStream流,再是body,而不是一起写入,所以当我们修改body后再修改请求头的ContentLength已是无意义。在无法预知修改后body的长度情况下,解决方案可以是将请求头的ContentLength移除,取而代之的是Transfer-Encoding: chunked。
统一校验Token有效性
在还是使用nginx做请求转发的时候,每个微服务都需要写一套token校验逻辑,如通过拦截器校验请求是否携带token,以及token是否有效。而获取用户信息需要先从请求头获取token,再查redis获取用户身份信息。
在引入网关后,我们就只需要在网关做token校验,校验通过后从redis获取用户信息,并写到请求头中,同时将Token从请求头移除。userId由网关传递给后台微服务,后台微服务不需要再一次根据Token获取用户ID。
统一校验资源访问权限
在引入网关后,除了登录(Token)校验,用户访问资源的权限校验都可以在网关实现,每个微服务都不再关心权限校验的问题。
具体的用户资源访问权限校验依然由用户中心完成,网关只负责调用用户中心提供的权限校验接口完成用户资源访问权限校验。这可能会影响接口的性能,尽量让用户中心在实现权限校验接口时数据来源全部读缓存。
对外开放api统一签名校验
我们对外开放API采用基于签名机制实现身份认证,可以控制签名的有限时间。笔者之前写过一篇关于签名机制的文章:《一种基于签名算法且简单安全的API授权机制》。
在没有引入网关之前,我们通过AOP实现,只需要在开放API方法上添加一个注解。其中key和私钥、签名有效期在配置文件中配置。而在引入网关后,就可以统一在网关实现签名校验。
如果API需要提供给多个不同主体使用,也就是会有多个合作客户的系统使用,那么key和密钥是要在后台提供配置功能的,且配置持久化到数据库,网关也需要支持根据key查询密钥再校验签名。网关可将key、密钥字典缓存在内存中,定时刷新。或者缓存到redis,当有账号的密钥更新时同步刷新缓存。
总结
网关一般用于统一流量入口、统一认证鉴权、流量控制,除此之外,一些与业务无关的重复操作也都可以在网关统一实现,如本篇介绍的统一SwaggerAPI文档入口,为文件url自动去掉或拼接域名与路由。内部对外提供的接口也都可以通过网关做签名校验、访问频率限制等。
本文转载自微信公众号「Java艺术」,可以通过以下二维码关注。转载本文请联系Java艺术公众号。