RequestContextHolder多线程获取不到request对象
创始人
2025-01-15 21:40:06
0

RequestContextHolder多线程获取不到request对象,调用feign接口时,在Feign中的RequestInterceptor也获取不到HttpServletRequest问题解决方案。

1.RequestContextHolder多线程获取不到request对象
异常信息,报错如下:

2024-07-09 22:06:32.320 [pool-5-thread-2] ERROR com.mergeplus.handler.ObjectHandler:227 - class: interface org.jeecg.common.system.api.client.SysFeignClient, methodName=mergeRegion, error: {} java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.  at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)  at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:313)  at org.springframework.web.context.support.WebApplicationContextUtils$RequestObjectFactory.getObject(WebApplicationContextUtils.java:329)  at org.springframework.web.context.support.WebApplicationContextUtils$RequestObjectFactory.getObject(WebApplicationContextUtils.java:324)  at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:283)  at jdk.proxy2/jdk.proxy2.$Proxy179.getHeaderNames(Unknown Source)  at com.mergeplus.handler.ObjectHandler.lambda$doHandler$0(ObjectHandler.java:155)  at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1768)  at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java)  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)  at java.base/java.lang.Thread.run(Thread.java:833) 

异常错误截图:
在这里插入图片描述
2.解决方案

        // 设置子线程共享(重点)         final RequestAttributes attributes = RequestContextHolder.getRequestAttributes();          merges.stream().map(e -> CompletableFuture.supplyAsync(() -> {             JSONObject returnMap = null;             try {                 if (e.getClientBean() != null) {                     // 设置当前线程的 RequestAttributes(重点)                     RequestContextHolder.setRequestAttributes(attributes);                      Object returnValue = e.getMethod().invoke(e.getClientBean(), jsonObject.get(e.getSourceKey()));                     if (returnValue == null) {                         return e;                     }                     returnMap = JSON.parseObject(JSON.toJSONString(returnValue));                      if (returnMap == null || returnMap.isEmpty()) {                         return e;                     }                      result.put(e.getTargetKey(), returnMap.get(jsonObject.get(e.getSourceKey())));                 } else {                     if (e.getUrl() == null || e.getUrl().trim().length() == 0) {                         return e;                     }                      //设置Http的Header                     HttpHeaders headers = new HttpHeaders();                     headers.setContentType(MediaType.APPLICATION_JSON);                      //设置访问参数                     HashMap params = new HashMap<>();                     if (e.getKey() == null || e.getKey().trim().length() == 0) {                         params.put(e.getSourceKey(), jsonObject.get(e.getSourceKey()));                     }                     //设置访问的Entity                     HttpEntity entity = new HttpEntity<>(params, headers);                      // todo                     ResponseEntity exchange = restTemplate.exchange(e.getUrl(), HttpMethod.GET, entity, Object.class);                     if (exchange == null) {                         return e;                     }                      Object body = exchange.getBody();                     if (body == null) {                         return e;                     }                      returnMap = JSON.parseObject(JSON.toJSONString(body));                     if (returnMap == null || returnMap.isEmpty()) {                         return e;                     }                      result.put(e.getTargetKey(), returnMap.get(jsonObject.get(e.getSourceKey())));  //                    if (body instanceof Map) { //                        returnMap = (Map) body; //                        if (returnMap == null || returnMap.isEmpty()) { //                            return e; //                        } //                        result.put(e.getTargetKey(), returnMap.get(jsonObject.get(e.getSourceKey()))); //                    }                 }             } catch (Exception ex) {                 log.error("class: {}, methodName={}, error: {}", e.getClientBeanClazz(), e.getMethod().getName(), ex);             } finally {                 RequestContextHolder.resetRequestAttributes(); // 记得在最后重置请求属性(重点)             }             return e;         }, executor)).toList().stream().map(CompletableFuture::join).collect(Collectors.toList());  

在这里插入图片描述
在这里插入图片描述
FeignInterceptorConfig代码

package org.jeecg.config;  import java.io.IOException; import java.util.*;   import feign.RequestTemplate; import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.jeecg.common.config.mqtoken.UserTokenContext; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.util.DateUtils; import org.jeecg.common.util.PathMatcherUtil; import org.jeecg.common.util.SpringContextUtils; import org.jeecg.common.util.TokenUtils; import org.jeecg.config.sign.interceptor.SignAuthConfiguration; import org.jeecg.config.sign.util.HttpUtils; import org.jeecg.config.sign.util.SignUtil; import org.springframework.beans.factory.ObjectFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignAutoConfiguration; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Scope; import org.springframework.http.MediaType; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;  import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;  import feign.Feign; import feign.Logger; import feign.RequestInterceptor; import feign.codec.Decoder; import feign.codec.Encoder; import feign.form.spring.SpringFormEncoder; import lombok.extern.slf4j.Slf4j;  /**  * @Description: FeignConfig  * @author: JeecgBoot  */ @ConditionalOnClass(Feign.class) @AutoConfigureBefore(FeignAutoConfiguration.class) @Slf4j @Configuration public class FeignInterceptorConfig {      @Bean     public RequestInterceptor requestInterceptor() {         return requestTemplate -> {             ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();             if (requestAttributes == null) {                 return;             }             //1.获取请求对象             HttpServletRequest request = requestAttributes.getRequest();             Enumeration headerNames = request.getHeaderNames();              if (headerNames == null || !headerNames.hasMoreElements()) {                 return;             }             //2.获取请求对象中的所有的头信息(网关传递过来的)             while (headerNames.hasMoreElements()) {                 String name = headerNames.nextElement();//头的名称                 // 跳过content-length,不然可能会报too many bites written问题                 if ("content-length".equalsIgnoreCase(name)) {                     continue;                 }                 String value = request.getHeader(name);//头名称对应的值                 // System.out.println("name:" + name + "::::::::value:" + value);                 //3.将头信息传递给feign (restTemplate)                 requestTemplate.header(name,value);  //                if (CommonConstant.X_ACCESS_TOKEN.equals(name) && StringUtils.isBlank(value)) { //                    String token = UserTokenContext.getToken(); //                    requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token); //                }              }              //================================================================================================================             //针对特殊接口,进行加签验证 ——根据URL地址过滤请求 【字典表参数签名验证】             // todo             if (PathMatcherUtil.matches(Arrays.asList(PathMatcherUtil.SIGN_URL_LIST),requestTemplate.path())) { //            if (PathMatcherUtil.matches(Arrays.asList(SignAuthConfiguration.SIGN_URL_LIST),requestTemplate.path())) {                 try {                     log.info("============================ [begin] fegin api url ============================");                     log.info(requestTemplate.path());                     log.info(requestTemplate.method());                     String queryLine = requestTemplate.queryLine();                     String questionMark="?";                     if(queryLine!=null && queryLine.startsWith(questionMark)){                         queryLine = queryLine.substring(1);                     }                     log.info(queryLine);                     if(requestTemplate.body()!=null){                         log.info(new String(requestTemplate.body()));                     }                     SortedMap allParams = HttpUtils.getAllParams(requestTemplate.path(),queryLine,requestTemplate.body(),requestTemplate.method());                     String sign = SignUtil.getParamsSign(allParams);                     log.info(" Feign request params sign: {}",sign);                     log.info("============================ [end] fegin api url ============================");                     requestTemplate.header(CommonConstant.X_SIGN, sign);                     requestTemplate.header(CommonConstant.X_TIMESTAMP, String.valueOf(System.currentTimeMillis()));                 } catch (IOException e) {                     e.printStackTrace();                 }             }             //================================================================================================================          };     }  } 

3.相关大数据学习demo地址:
https://github.com/carteryh/big-data

相关内容

热门资讯

第3分钟了解(aapoker讲... 第3分钟了解(aapoker讲解)外挂辅助下载(辅助挂)科技教程(2026已更新)(哔哩哔哩);aa...
第七分钟熟悉!wepoker辅... 第七分钟熟悉!wepoker辅助插件功能,德普之星辅助工具如何打开,总结教程(有挂秘籍)-哔哩哔哩1...
4阶段了解!兴动互娱辅助器,w... 4阶段了解!兴动互娱辅助器,wepoker亲友圈有用吗,教你攻略(有挂详情)1、玩家可以在兴动互娱辅...
第7分钟了解“哈灵小程序脚本”... 第7分钟了解“哈灵小程序脚本”详细透视开挂辅助安装-哔哩哔哩;大家肯定在之前哈灵小程序脚本或者哈灵小...
八分钟了解(钱柜手游)外挂辅助... 八分钟了解(钱柜手游)外挂辅助挂(透视)详细教程(2020已更新)(哔哩哔哩);亲真的是有正版授权,...
七分钟透视!aapoker辅助... 七分钟透视!aapoker辅助工具免费下载,wepoker透视方法,插件教程(有挂方式)-哔哩哔哩1...
第5些了解!仙神互娱辅助,智星... 第5些了解!仙神互娱辅助,智星菠萝辅助怎么买,2025新版(有挂头条)该软件可以轻松地帮助玩家将仙神...
8分钟了解“微信雀神小程序插件... 8分钟了解“微信雀神小程序插件”详细透视开挂辅助攻略-哔哩哔哩;是一款可以让一直输的玩家,快速成为一...
第6分钟了解(pokerwor... 第6分钟了解(pokerworld软件)外挂辅助软件(透视)详细教程(2024已更新)(哔哩哔哩)是...
第5分钟黑科技!aapoker... 第5分钟黑科技!aapoker破解侠是真的吗,智星菠萝可以辅助吗,教你攻略(有挂解密)-哔哩哔哩第5...