13、Feign请求拦截器RequestInterceptor源码分析及使用案例

需求场景

在使用Spring Security Oauth2时,通过消息头中的Authorization Bearer toeknXXXX对令牌进行校验,如果失败,是会拒绝访问的。

那么在使用Feign进行调用时,就会出现问题,因为Feign发送请求时,是没有传递认证消息头的。

解决方案

实现RequestInterceptor,获取原本请求中的认证消息头,然后添加到请求模板中。

@Component
public class Oauth2TokenRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {

        // 获取请求中的消息头
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String requestHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (StringUtils.isNotBlank(requestHeader) && requestHeader.startsWith("Bearer ")) {

            // 将消息头塞入到请求模板中
            requestTemplate.header(HttpHeaders.AUTHORIZATION, requestHeader);
        }
    }
}

测试,可以看到Feign请求成功传递了消息头。
 

源码分析

在创建SynchronousMethodHandler时,可以看到,会将从配置或者IOC中查找请求拦截器,并赋值给自己。
 
在通过请求模板创建请求对象时,会迭代拦截器,并调用其 apply,将消息头放入到请求模板中。
 
最终在发送请求时,请求头中就包含拦截器设置的消息头了。
 

FeignClient 注解中配置请求拦截器

也可以直接在@FeignClient注解中,直接添加拦截器,它只作用于当前Feign 客户端,比如:

@FeignClient(name = "order-service",configuration = {

     BBBRequestInterceptor.class})

此时,全局的、客户端自己的,会在请求时,加入到请求拦截器链中,循环执行。