记录一些遇见的bug——记录一个使用多线程异步调用openfeign时子线程丢失request请求头导致的空指针异常错误
Posted 叶不修233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录一些遇见的bug——记录一个使用多线程异步调用openfeign时子线程丢失request请求头导致的空指针异常错误相关的知识,希望对你有一定的参考价值。
记录一些遇见的bug——记录一个使用多线程异步调用openfeign时子线程丢失request请求头导致的空指针异常错误
1.出现问题的业务逻辑
List<MyData> demo()
//异步往CompletableFuture中存数据
List<CompletableFuture<MyData>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++)
//开启10个线程异步调用openfeign请求,往CompletableFuture中存方法返回的数据
futures.add(this.loadData(args));
//从CompletableFuture中取数据
List<MyData> myDataList = new ArrayList<>();
for (CompletableFuture<MyData> future : futures)
MyData myData = future.get();
if (myData == null)
continue;
myDataList.add(myData);
return myDataList;
CompletableFuture<MyData> loadData(String args)
return CompletableFuture.supplyAsync(() ->
//异步调用openfeign请求获取数据
MyData myData = myGetDataClient.getData(args);
return myData;
);
2.错误日志
Caused by: java.lang.NullPointerException: null
at com.flybees.config.FeignConfig.apply(FeignConfig.java:78)
at feign.SynchronousMethodHandler.targetRequest(SynchronousMethodHandler.java:176)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:101)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:80)
at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:109)
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:302)
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:298)
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46)
... 67 common frames omitted
3.原因分析
查看feign配置FeignConfig.java
获取request对象的请求头时报了空指针异常,意思就是主线程中的请求头并没有带过来
@Configuration
public class FeignConfig implements RequestInterceptor
@Override
public void apply(RequestTemplate requestTemplate)
/*
* 获取原线程的request对象的请求头中的token
* RequestContextHolder.getRequestAttributes():获取request原始的请求头对象
* 接口类RequestAttributes不能使用,所以强转为ServletRequestAttributes类型
*/
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//获取原Request对象
HttpServletRequest request = servletRequestAttributes.getRequest();
//把原request的请求头的所有参数都拿出来
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements())
//获取每个请求头参数的名字
String name = headerNames.nextElement();
//获取值
String value = request.getHeader(name);
// 跳过 content-length,用于解决Caused by: feign.RetryableException: too many bytes written executing POST http://xx报错
if (name.equalsIgnoreCase("content-length"))
continue;
//放到feign调用对象的request中去
requestTemplate.header(name, value);
4.解决方案
在主线程里调用子线程时将request传递过去,并设置子线程的请求头
List<MyData> demo(String args)
//异步往CompletableFuture中存数据
List<CompletableFuture<MyData>> futures = new ArrayList<>();
//获取当前线程(主线程)请求头对象(增)
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
for (int i = 0; i < 10; i++)
//开启10个线程异步调用openfeign请求,往CompletableFuture中存方法返回的数据(改)
futures.add(this.loadData(args,requestAttributes);
//从CompletableFuture中取数据
List<MyData> myDataList = new ArrayList<>();
for (CompletableFuture<MyData> future : futures)
MyData myData = future.get();
if (myData == null)
continue;
myDataList.add(myData);
return myDataList;
CompletableFuture<MyData> loadData(String args, RequestAttributes requestAttributes)
return CompletableFuture.supplyAsync(() ->
try
//将主线程的request请求头传递到子线程,防止异步时发生子线程request请求头丢失的情况(改)
RequestContextHolder.setRequestAttributes(requestAttributes);
//在异步子线程中调用openfeign请求获取数据
MyData myData = myGetDataClient.getData(args);
return myData;
finally
//清除子线程请求头信息(增)
RequestContextHolder.resetRequestAttributes();
);
以上是关于记录一些遇见的bug——记录一个使用多线程异步调用openfeign时子线程丢失request请求头导致的空指针异常错误的主要内容,如果未能解决你的问题,请参考以下文章
记录一些遇见的bug——调用增加方法报错line 1:43 no viable alternative at input ‘<EOF>‘ line 1:43 mismatched input ‘<EO
记录一些遇见的bug——调用增加方法报错line 1:43 no viable alternative at input ‘<EOF>‘ line 1:43 mismatched input ‘<EO
记录一些遇见的bug——关于Lombok的一个大坑,使用@RequestBody接收axios请求对象时,对象所有属性均为null
记录一些遇见的bug——关于Lombok的一个大坑,使用@RequestBody接收axios请求对象时,对象所有属性均为null