1、feign 远程调用丢失请求头的问题
原因:feign不会同步request的请求头。
解决方案:使用interceptor将用户请求的请求头设置给feign代理的请求
/**
* @DESCRIPTION feign的请求拦截器,用于将用户请求头设置给feign代理后的请求,防止代理后丢失请求头
* @Author yaya
* @DATE 2022/10/7
*/
@Configuration
public class FeignInterceptor {
@Bean("requestInterceptor")
public RequestInterceptor requestInterceptor(){
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
// 通过RequestContextHolder拿到用户的request
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
String cookie = request.getHeader("Cookie");
// 将用户的cookie设置给feign代理后的请求
requestTemplate.header("Cookie", cookie);
}
};
}
}
源代码跟踪:
1、feign远程调用首先会进ReflectiveFeign.invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!"equals".equals(method.getName())) {
if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else {
// 如果不是hashCode、toString方法则会调用目标方法
return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
}
} else {
try {
Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return this.equals(otherHandler);
} catch (IllegalArgumentException var5) {
return false;
}
}
}
2、然后会进到SynchronousMethodHandler.invoke方法
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = this.buildTemplateFromArgs.create(argv);
Options options = this.findOptions(argv);
Retryer retryer = this.retryer.clone();
while(true) {
try {
return this.executeAndDecode(template, options);
} catch (RetryableException var9) {
RetryableException e = var9;
try {
retryer.continueOrPropagate(e);
} catch (RetryableException var8) {
Throwable cause = var8.getCause();
if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {
throw cause;
}
throw var8;
}
if (this.logLevel != Level.NONE) {
this.logger.logRetry(this.metadata.configKey(), this.logLevel);
}
}
}
}
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
Request request = this.targetRequest(template);
if (this.logLevel != Level.NONE) {
this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
}
long start = System.nanoTime();
Response response;
try {
response = this.client.execute(request, options);
response = response.toBuilder().request(request).requestTemplate(template).build();
} catch (IOException var13) {
if (this.logLevel != Level.NONE) {
this.logger.logIOException(this.metadata.configKey(), this.logLevel, var13, this.elapsedTime(start));
}
throw FeignException.errorExecuting(request, var13);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
if (this.decoder != null) {
return this.decoder.decode(response, this.metadata.returnType());
} else {
CompletableFuture<Object> resultFuture = new CompletableFuture();
this.asyncResponseHandler.handleResponse(resultFuture, this.metadata.configKey(), response, this.metadata.returnType(), elapsedTime);
try {
if (!resultFuture.isDone()) {
throw new IllegalStateException("Response handling not done");
} else {
return resultFuture.join();
}
} catch (CompletionException var12) {
Throwable cause = var12.getCause();
if (cause != null) {
throw cause;
} else {
throw var12;
}
}
}
}
在executeAndDecode方法中会执行一行代码Request request = this.targetRequest(template);这个方法就是处理request的逻辑。
3、targetRequest处理request
Request targetRequest(RequestTemplate template) {
// 遍历执行interceptor
Iterator var2 = this.requestInterceptors.iterator();
while(var2.hasNext()) {
RequestInterceptor interceptor = (RequestInterceptor)var2.next();
interceptor.apply(template);
}
return this.target.apply(template);
}
在targetRequest方法中会遍历执行interceptor。
private final List
requestInterceptors;
我们往容器中放的interceptor就会被执行,request中就会有请求头了。
2、feign异步情况丢失上下文
原因:异步请求,request不是同一个,threadLocal中获取不到。
解决方案:在异步编排时手动在新线程中共享下数据:RequestContextHolder.setAttribute()。
原文地址:http://www.cnblogs.com/yanghuanxi/p/16817992.html
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,请务用于商业用途!
3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员!
8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载
声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性