![微服务分布式架构基础与实战:基于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=1738862824-jDUijRdxXTayX8p8XvGfcIMFpkwJJUBC-0-ebb954f827ea6bf449c1c2b1606ce5f1)
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=1738862824-Aud7wPV7kKCASHRTRck4gHEejscrTvKN-0-a90703efe189f040a6d881615e8558bd)
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_92_3.jpg?sign=1738862824-5EarYasA2S0TpugAOIP1cSeXYrRkyX9x-0-9e3a5cd31a8ffb1c03a1f7aba94279a6)
图3-20
客户端在实例化请求前,先进入拦截器,然后请求其他微服务,其后台日志如图3-21所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_92_4.jpg?sign=1738862824-05E3EC3IRHREfaoPicK10h7o9FvENlvd-0-8a33ee39904cd72cdff8130c65eeccc2)
图3-21
3.4.5 实例易错点
1.HTTP编码格式错误
如果发生HTTP编码格式错误,控制台会输出错误信息如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_93_1.jpg?sign=1738862824-UoF1zxGRNPwbs4NYxK7FTrQyuiKDBNNp-0-d923975f57d7a3f804cb50411b977464)
此时需要在拦截器中添加header报文头,更改HTTP编码格式为
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_93_2.jpg?sign=1738862824-VEnOFaWcxEj6cM1cJQy4rWb8KZnH3J3O-0-a9a4079e36dc1e2e51db88ace8cedac3)
由于此处没有编辑器校验,所以容易写错,若写错,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=1738862824-bfJxv0Ckf9i9pqDnodwHGk7L2HC65vzy-0-98be80a326542a3261d895d8cd085229)
2.Feign拦截器需注册到Spring容器中
如果没有将Feign拦截器作为Bean注册到Spring容器中,相当于没有自定义拦截器,不会发生其他任何异常。若没有注册到Spring容器中,可用编程的方式实例化FeignClient,伪代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_93_4.jpg?sign=1738862824-djSMphrRHPmB02o1VZH0dGeMSsTcAYuC-0-69ec4e4e1c1c1bd4477faa5fc9a7dcdb)
通过代码构造了Feign的Client端,构造时已经将拦截器作为构造参数使用,因此不需要将Feign拦截器注册到Spring容器中。除上述方式外,将拦截器配置到application.yml资源配置文件中,也不需要将拦截器作为Bean注册到Spring容器中,配置代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_94_1.jpg?sign=1738862824-MnmptuigBJDSGemtkBnh8uvFNYXK9nL4-0-ef86cf6cb7e49f4127fccad119519463)
此时需注意以下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=1738862824-2OukwqKFcr5018XJndDprGAdxQoLBhhk-0-68ce7c6777124646e24f14c4e4d880d3)
图3-22