关于feign调用请求头丢失分析

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那里可以获取到服务携带过滤的请求头;

原文地址:https://www.cnblogs.com/coder-zyc/p/14811644.html