3.4 【实例】Feign的拦截器
3.4.1 实例背景
Feign的拦截器是在Client端进行编写的,Client端在调用Server端前,会在自身内部进行Feign拦截。通常拦截是为了在Request Header报文头内部增加token之类的信息,使Feign在调用前统一处理请求/请求头/请求体。
本实例继续修改3.3节中的cloud-admin-8084工程,通过实现Feign的拦截器保证每次Feign的调用都会被拦截函数进行拦截。
3.4.2 在cloud-admin-8084工程中增加拦截器
通过实现feign.RequestInterceptor接口,来实现Feign的拦截器。使用@Configuration注解将Feign的拦截器注册到Spring容器上。在编写Feign拦截器Interceptor拦截器实现类的过程中,需要重写并实现apply函数,编写完该函数后,每次Feign请求都会经过AdminInterceptor拦截器。
AdminInterceptor.java拦截器的实现代码如下。
RequestTemplate是请求模板,即非线程安全的模板模型,可任意修改,所以通过复杂构造函数进行实现,请求对象都通过请求模板进行实例化。请求模板是Feign拦截器最重要的部分,RequestTemplate的使用方法非常简单,直接使用其中的函数即可。
3.4.3 当前项目结构
如图3-20所示,增加Feign的拦截器只需要增加AdminInterceptor.java类即可,不需要增加其他内容。
3.4.4 运行结果
在调用请求时,先进入拦截器,然后通过LoadBalancer实例化Feign的负载均衡器,代码如下。
图3-20
客户端在实例化请求前,先进入拦截器,然后请求其他微服务,其后台日志如图3-21所示。
图3-21
3.4.5 实例易错点
1.HTTP编码格式错误
如果发生HTTP编码格式错误,控制台会输出错误信息如下。
此时需要在拦截器中添加header报文头,更改HTTP编码格式为
由于此处没有编辑器校验,所以容易写错,若写错,Feign进入拦截器更改HTTP编码格式传输到Server端的时候,发生Client端的调用错误。注意,Feign不接受get请求进行实体类POJO作为参数传递,解决方案如下。
(1)将POJO转换成Map进行传递。
(2)将POJO拆分成多个参数再进行传递。
(3)入参以@ModelAttribute注解修饰,被@ModelAttribute注解修饰后,POJO会作为字符串拼接在URL上。但如果将POJO拆分成多个参数,URL过长可能会影响性能。
若在通常情况下Server服务提供方和Feign Client调用方的入参、出参等函数完全相同,则不会出现较多问题,代码如下。
2.Feign拦截器需注册到Spring容器中
如果没有将Feign拦截器作为Bean注册到Spring容器中,相当于没有自定义拦截器,不会发生其他任何异常。若没有注册到Spring容器中,可用编程的方式实例化FeignClient,伪代码如下。
通过代码构造了Feign的Client端,构造时已经将拦截器作为构造参数使用,因此不需要将Feign拦截器注册到Spring容器中。除上述方式外,将拦截器配置到application.yml资源配置文件中,也不需要将拦截器作为Bean注册到Spring容器中,配置代码如下。
此时需注意以下4点。
(1)feign.client.config.cloud-user.requestInterceptors中对应的数据相当于一个数组,可以多个叠加。
(2)“-”减号后有一个空格,“-”减号前比requestInterceptors节点前多两个空格。
(3)当前FeignClient的名字为cloud-user,上述配置是添加在cloud-admin-8084工程中的,但由于实例化的是cloud-user接口,所以FeignClient的名字为cloud-user。若拦截器较复杂,则推荐用资源配置的写法。如果要设置全局配置,可以将cloud-user改为default,即feign.client.config.default下为Feign拦截器的默认配置。
(4)不要将Feign拦截器注册到Spring容器中的同时,又在资源配置文件中进行配置,否则该场景下Feign会两次进入拦截器,输出日志如图3-22所示。
图3-22