当前位置: 首页 > news >正文

springboot项目异步处理获取不到header中的token

controller方法中调用service的方法,service方法上@Async代表异步执行这个方法,此时方法中如果获取请求头中的token是获取不到的,获取方式如下:

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
String tokenValue = request.getHeader(tokenHeaderKey);

具体原因:

public static RequestAttributes getRequestAttributes() {RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();if (attributes == null) {attributes = (RequestAttributes)inheritableRequestAttributesHolder.get();}return attributes;
}
private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");

可以看到采用的ThreadLocal存储的request对象,所以子线程魂总获取不到主线程的request。解决办法重新创建request对象,传参给service中异步方法。首先自定义request对象

package com.erbaoge.common.utils;import javax.servlet.*;
import javax.servlet.http.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.*;/*** 实现 javax.servlet.http.HttpServletRequest 方法主要用于在子线程中获取参数* 目前只实现headers 和 parameters 其他属性可自定义* @since 2025/9/15 15:44*/
public class ServletRequestCustom implements HttpServletRequest {private Map<String, Vector<String>> headersMap;private Map<String, String[]> paraMap;public ServletRequestCustom() {headersMap = new HashMap<>();paraMap = new HashMap<>();}public ServletRequestCustom(HttpServletRequest request){this();setHeaders(request);setParameters(request);}private void setParameters(HttpServletRequest request) {Enumeration<String> parameterNames = request.getParameterNames();while (parameterNames.hasMoreElements()){String key = parameterNames.nextElement();paraMap.put(key, request.getParameterValues(key));}}private void setHeaders(HttpServletRequest request) {Enumeration<String> headerNames = request.getHeaderNames();while (headerNames.hasMoreElements()) {String key = headerNames.nextElement();Enumeration<String> headers = request.getHeaders(key);Vector<String> vector = new Vector<>();while (headers.hasMoreElements()) {vector.add(headers.nextElement());}headersMap.put(key, vector);}}@Overridepublic String getAuthType() {return "";}@Overridepublic Cookie[] getCookies() {return new Cookie[0];}@Overridepublic long getDateHeader(String s) {return 0;}@Overridepublic String getHeader(String s) {Vector<String> vector = headersMap.get(s);return vector.isEmpty() ? null : vector.get(0);}@Overridepublic Enumeration<String> getHeaders(String s) {return headersMap.get(s.toLowerCase()).elements();}@Overridepublic Enumeration<String> getHeaderNames() {Iterator<String> iterator = headersMap.keySet().iterator();return new Enumeration<String>() {@Overridepublic boolean hasMoreElements() {return iterator.hasNext();}@Overridepublic String nextElement() {return iterator.next();}};}@Overridepublic int getIntHeader(String s) {return 0;}@Overridepublic String getMethod() {return "";}@Overridepublic String getPathInfo() {return "";}@Overridepublic String getPathTranslated() {return "";}@Overridepublic String getContextPath() {return "";}@Overridepublic String getQueryString() {return "";}@Overridepublic String getRemoteUser() {return "";}@Overridepublic boolean isUserInRole(String s) {return false;}@Overridepublic Principal getUserPrincipal() {return null;}@Overridepublic String getRequestedSessionId() {return "";}@Overridepublic String getRequestURI() {return "";}@Overridepublic StringBuffer getRequestURL() {return null;}@Overridepublic String getServletPath() {return "";}@Overridepublic HttpSession getSession(boolean b) {return null;}@Overridepublic HttpSession getSession() {return null;}@Overridepublic String changeSessionId() {return "";}@Overridepublic boolean isRequestedSessionIdValid() {return false;}@Overridepublic boolean isRequestedSessionIdFromCookie() {return false;}@Overridepublic boolean isRequestedSessionIdFromURL() {return false;}@Overridepublic boolean isRequestedSessionIdFromUrl() {return false;}@Overridepublic boolean authenticate(HttpServletResponse httpServletResponse) throws IOException, ServletException {return false;}@Overridepublic void login(String s, String s1) throws ServletException {}@Overridepublic void logout() throws ServletException {}@Overridepublic Collection<Part> getParts() throws IOException, ServletException {return Collections.emptyList();}@Overridepublic Part getPart(String s) throws IOException, ServletException {return null;}@Overridepublic <T extends HttpUpgradeHandler> T upgrade(Class<T> aClass) throws IOException, ServletException {return null;}@Overridepublic Object getAttribute(String s) {return null;}@Overridepublic Enumeration<String> getAttributeNames() {return null;}@Overridepublic String getCharacterEncoding() {return "";}@Overridepublic void setCharacterEncoding(String s) throws UnsupportedEncodingException {}@Overridepublic int getContentLength() {return 0;}@Overridepublic long getContentLengthLong() {return 0;}@Overridepublic String getContentType() {return "";}@Overridepublic ServletInputStream getInputStream() throws IOException {return null;}@Overridepublic String getParameter(String s) {String[] values = paraMap.get(s);return values.length > 0 ? values[0] : null;}@Overridepublic Enumeration<String> getParameterNames() {final Iterator<String> iterator = paraMap.keySet().iterator();return new Enumeration<String>() {@Overridepublic boolean hasMoreElements() {return iterator.hasNext();}@Overridepublic String nextElement() {return iterator.next();}};}@Overridepublic String[] getParameterValues(String s) {return paraMap.get(s);}@Overridepublic Map<String, String[]> getParameterMap() {return new HashMap<>(paraMap);}@Overridepublic String getProtocol() {return "";}@Overridepublic String getScheme() {return "";}@Overridepublic String getServerName() {return "";}@Overridepublic int getServerPort() {return 0;}@Overridepublic BufferedReader getReader() throws IOException {return null;}@Overridepublic String getRemoteAddr() {return "";}@Overridepublic String getRemoteHost() {return "";}@Overridepublic void setAttribute(String s, Object o) {}@Overridepublic void removeAttribute(String s) {}@Overridepublic Locale getLocale() {return null;}@Overridepublic Enumeration<Locale> getLocales() {return null;}@Overridepublic boolean isSecure() {return false;}@Overridepublic RequestDispatcher getRequestDispatcher(String s) {return null;}@Overridepublic String getRealPath(String s) {return "";}@Overridepublic int getRemotePort() {return 0;}@Overridepublic String getLocalName() {return "";}@Overridepublic String getLocalAddr() {return "";}@Overridepublic int getLocalPort() {return 0;}@Overridepublic ServletContext getServletContext() {return null;}@Overridepublic AsyncContext startAsync() throws IllegalStateException {return null;}@Overridepublic AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {return null;}@Overridepublic boolean isAsyncStarted() {return false;}@Overridepublic boolean isAsyncSupported() {return false;}@Overridepublic AsyncContext getAsyncContext() {return null;}@Overridepublic DispatcherType getDispatcherType() {return null;}
}

contoller中方法注入HttpServletRequest对象,并创建自定义request对象

@GetMapping("/test")
public Result<?> test (HttpServletRequest request) {ServletRequestCustom servletRequestCustom = new ServletRequestCustom(request);lotteryService.test(servletRequestCustom);return Result.success();
}

service中异步方法需要将request放入

@Async
@Override
public void test(HttpServletRequest request) {RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));try {......} finally {RequestContextHolder.resetRequestAttributes();}
}

上述方法是spring的异步执行方法,方法中就能成功使用开始的那种方式获取到token。

两点疑问

  1. 为什么不直接传参从controller中注入的request对象
  2. 为什么不在controller线程中获取ServletRequestAttributes后,再放入,子线程获取参数传参true。使用代码
    RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request), true);

答案是以上两种方式都不能成功在异步方法中获取token,详细原因还未深究。


文章转载自:

http://bdoVJCVM.npgwb.cn
http://8DotgKIW.npgwb.cn
http://wI1CGDrj.npgwb.cn
http://DdbuH6KR.npgwb.cn
http://gOLLdL94.npgwb.cn
http://E5QVXKH0.npgwb.cn
http://55eyW131.npgwb.cn
http://8s7ywDMW.npgwb.cn
http://PHRtneqN.npgwb.cn
http://6e0jqBf2.npgwb.cn
http://3rxZp3jd.npgwb.cn
http://CM79UCAO.npgwb.cn
http://Bi7DR3UC.npgwb.cn
http://hp8bAX80.npgwb.cn
http://LsWnXguJ.npgwb.cn
http://tk7HrHCo.npgwb.cn
http://pMvhuCBB.npgwb.cn
http://kShUHjoD.npgwb.cn
http://xPTSSbuq.npgwb.cn
http://vtHxgxsF.npgwb.cn
http://wuRDrCUI.npgwb.cn
http://Vffa4PRA.npgwb.cn
http://ETFxqT1s.npgwb.cn
http://MKrdPa7g.npgwb.cn
http://I6HDqrBC.npgwb.cn
http://fAZYAOin.npgwb.cn
http://aZhFaoEe.npgwb.cn
http://Th8RUK04.npgwb.cn
http://VYfkD1i1.npgwb.cn
http://BcEOZKTP.npgwb.cn
http://www.dtcms.com/a/384815.html

相关文章:

  • Vue 输入库长度限制的实现
  • 嵌入式硬件——IMX6ULL 裸机LED点亮实验
  • 【左程云算法笔记016】双端队列-双链表和固定数组实现
  • 鸿蒙深链落地实战:从安全解析到异常兜底的全链路设计
  • [创业之路-585]:初创公司的保密安全与信息公开的效率提升
  • 【WitSystem】详解JWT在系统登录过程中前端做了什么事,后端又做了什么事?
  • 力扣(LeetCode) ——217. 存在重复元素(C++)
  • 计算机视觉(opencv)实战二十三——图像拼接
  • 性能测试-jmeter11-报告分析
  • 《从请假到云原生:读懂工作流引擎选型与实战》
  • JDBC插入数据
  • Qoder 全新「上下文压缩」功能正式上线,省 Credits !
  • FPGA时序约束(五)--衍生时钟约束
  • 【C语言】第八课 输入输出与文件操作​​
  • 滤波器模块选型指南:关键参数与实用建议
  • 现有的双边拍卖机制——VCG和McAfee
  • Linux 系统、内核及 systemd 服务等相关知识
  • 企业级 Docker 应用:部署、仓库与安全加固
  • 倍福TwinCAT HMI如何关联PLC变量
  • 2025.9.25大模型学习
  • Java开发工具选择指南:Eclipse、NetBeans与IntelliJ IDEA对比
  • C++多线程编程:从基础到高级实践
  • JavaWeb 从入门到面试:Tomcat、Servlet、JSP、过滤器、监听器、分页与Ajax全面解析
  • Java 设计模式——分类及功能:从理论分类到实战场景映射
  • 【LangChain指南】输出解析器(Output parsers)
  • 答题卡识别改分项目
  • 【C语言】第七课 字符串与危险函数​​
  • Java 网络编程全解析
  • GD32VW553-IOT V2开发版【三分钟快速环境搭建教程 VSCode】
  • Docker 与 VSCode 远程容器连接问题深度排查与解决指南