feign是Spring Cloud提供的伪http客户端(本质还是用http),封装了Http调用流程,使用Java接口注解的方式无感知调用Http请求,不用像Ribbon中通过封装HTTP请求报文的方式调用,feign默认集成了Ribbon;
A服务通过feign接口调用B服务,A中带有请求头,但是请求到了服务B,请求头丢失了,如下图
当请求到了服务B的拦截器,获取请求头,此时请求头获取不到,如下图
原因如下:
当服务A调用feign接口的时候,调用服务B的请求是新创建的,跟服务A原有的请求不是不同一个,因此新创建的请求不能拿到之前的请求的所携带的参数;
feign.SynchronousMethodHandler#invoke
RequestTemplate的对象是新创建的;
创建后的RequestTemplate对象中的headers为空的;
之后执行到executeAndDecode方法,如下
feign.SynchronousMethodHandler#executeAndDecode
targetRequest方法里面是对请求进行拦截,下面的client.execute是执行Http请求;
feign.SynchronousMethodHandler#targetRequest.
RequestInterceptor是feign的请求拦截器,因此可以在这里做处理;
RequestInterceptor的继承树如下:
根据现有的实现,仿写如下:
private static final String ACCESSTOKEN_HEADER = "accessToken"; @Bean public RequestInterceptor requestInterceptor() { return template -> { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); log.info(request.getHeaderNames().toString()); template.header(ACCESSTOKEN_HEADER, request.getHeader(ACCESSTOKEN_HEADER)); } else { log.warn("requestInterceptor获取Header空指针异常"); } }; }
之后在服务B那里可以获取到服务携带过滤的请求头;