![微服务分布式架构基础与实战:基于Spring Boot + Spring Cloud](https://wfqqreader-1252317822.image.myqcloud.com/cover/390/31186390/b_31186390.jpg)
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拦截器的实现代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_92_1.jpg?sign=1738965127-k5UpKnVXVP0ijyRkY94nLPjGGbzHObKO-0-3fc7f7cdea212f06ed341daf21541c3f)
RequestTemplate是请求模板,即非线程安全的模板模型,可任意修改,所以通过复杂构造函数进行实现,请求对象都通过请求模板进行实例化。请求模板是Feign拦截器最重要的部分,RequestTemplate的使用方法非常简单,直接使用其中的函数即可。
3.4.3 当前项目结构
如图3-20所示,增加Feign的拦截器只需要增加AdminInterceptor.java类即可,不需要增加其他内容。
3.4.4 运行结果
在调用请求时,先进入拦截器,然后通过LoadBalancer实例化Feign的负载均衡器,代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_92_2.jpg?sign=1738965127-NEfCC2hlZ35BcYdp8KYcatzHT4ZSBNhe-0-8b79a848acef4d36b646e486da688dc5)
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_92_3.jpg?sign=1738965127-lyj4zjr42yLKjl1ipXRllDyK04Uf2kdG-0-16398dd37250d4555739656e653e3d53)
图3-20
客户端在实例化请求前,先进入拦截器,然后请求其他微服务,其后台日志如图3-21所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_92_4.jpg?sign=1738965127-yE2hz6SsXcvzFgWjGp11PThx27cjSoTT-0-4111f6e56929f70f5ef71c64123073e3)
图3-21
3.4.5 实例易错点
1.HTTP编码格式错误
如果发生HTTP编码格式错误,控制台会输出错误信息如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_93_1.jpg?sign=1738965127-sTbGnt9dDTtzuBif3mPzSeXRIIvMj6mQ-0-a35290df0344c1b76ca11887211cd455)
此时需要在拦截器中添加header报文头,更改HTTP编码格式为
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_93_2.jpg?sign=1738965127-wrCJgsxLXtOmOHS8p2nkwopfSGBZZ21o-0-cc4a30036cb93d524c157a57cf3d2fa1)
由于此处没有编辑器校验,所以容易写错,若写错,Feign进入拦截器更改HTTP编码格式传输到Server端的时候,发生Client端的调用错误。注意,Feign不接受get请求进行实体类POJO作为参数传递,解决方案如下。
(1)将POJO转换成Map进行传递。
(2)将POJO拆分成多个参数再进行传递。
(3)入参以@ModelAttribute注解修饰,被@ModelAttribute注解修饰后,POJO会作为字符串拼接在URL上。但如果将POJO拆分成多个参数,URL过长可能会影响性能。
若在通常情况下Server服务提供方和Feign Client调用方的入参、出参等函数完全相同,则不会出现较多问题,代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_93_3.jpg?sign=1738965127-DWwXc3YOZzBsZr0WUj2YgffJ0Ci5iZEs-0-380add24265048b9934b1262a63ac95b)
2.Feign拦截器需注册到Spring容器中
如果没有将Feign拦截器作为Bean注册到Spring容器中,相当于没有自定义拦截器,不会发生其他任何异常。若没有注册到Spring容器中,可用编程的方式实例化FeignClient,伪代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_93_4.jpg?sign=1738965127-C8hOYMgsPXpSEq2lMLnsbPv22Q7zST7y-0-dca6f4b2a67b2f61df3e166549c2d532)
通过代码构造了Feign的Client端,构造时已经将拦截器作为构造参数使用,因此不需要将Feign拦截器注册到Spring容器中。除上述方式外,将拦截器配置到application.yml资源配置文件中,也不需要将拦截器作为Bean注册到Spring容器中,配置代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_94_1.jpg?sign=1738965127-cAamkEQq7Do61rFTWWmK7bk4mER7Wtq4-0-c0c2a1887ab65c56f061e7a5d64f2f9c)
此时需注意以下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所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_94_2.jpg?sign=1738965127-NoCNDCGQT7U2R5oeJ4PpZHyQ8xn8uLXW-0-b95cb220d7d0b65ff6e6d3d1368baaf4)
图3-22