Spring Boot跨请求获取Session属性为Null问题求助
Spring Boot跨请求Session属性为Null问题排查
在Spring Boot项目中,调用/getproductlist接口设置HttpSession的currshop属性后,当前请求可正常获取该属性,但调用/insertBatch接口时,该属性始终为Null,触发NullPointerException。已排查两天仍未找到原因,请问这是浏览器问题还是代码存在遗漏?
相关代码
/getproductlist接口代码
@Autowired HttpSession httpSession; @GetMapping("/getproductlist") @CrossOrigin @ResponseBody public Map<String,Object> getproductlist(HttpServletRequest request,HttpSession session) { Map<String,Object> map = new HashMap<>(); shop currshop = new shop(); currshop.setShop_id(1l); request.getSession().setAttribute("currshop",currshop); httpSession.setAttribute("currshop",currshop); shop currshop2 = (com.o2o.shop.entity.shop) httpSession.getAttribute("currshop"); System.out.println("===================="+currshop2.getShop_id()); List<productCategory> list = null; if(currshop2 != null && currshop2.getShop_id() != null) { list = pcategoryService.queryProductCategoryList(currshop.getShop_id()); map.put("pcategory",list); }else{ map.put("success",false); } return map; }
当前请求可正常工作,但下一个请求中该属性始终为Null。
/insertBatch接口代码
@PostMapping(value = "/insertBatch") @CrossOrigin @ResponseBody public Map<String,Object> insertBatch(@RequestBody List<productCategory> pcategory,HttpServletRequest request) { Map<String,Object> map = new HashMap<>(); int a =-1; shop currshop2 = (com.o2o.shop.entity.shop) httpSession.getAttribute("currshop"); System.out.println("===================="+currshop2 .getShop_id()); for(productCategory pc : pcategory) { pc.setShop_id(currshop2 .getShop_id()); } if(pcategory != null && pcategory.size() != 0) { a = pcategoryService.insertBatch(pcategory); map.put("success",a); }else{ a=0; map.put("success","empty list"); } return map; }
报错信息
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) at javax.servlet.http.HttpServlet.service(HttpServlet.java:517) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:584) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656) at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:292) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:516) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:137) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.NullPointerException: null
问题根源与修复方案
1. 错误的HttpSession注入方式
HttpSession是请求作用域对象,不能直接用@Autowired注入到类中。你注入的httpSession是一个代理对象,但跨请求时无法关联到当前请求的真实Session,导致insertBatch接口拿到的Session和getproductlist的不是同一个,自然取不到属性。
修复:
- 删除类上的
@Autowired HttpSession httpSession; - 所有接口通过方法参数直接注入HttpSession,或者从HttpServletRequest中获取:
// 示例:getproductlist接口修正 @GetMapping("/getproductlist") @CrossOrigin(allowCredentials = true) @ResponseBody public Map<String,Object> getproductlist(HttpSession session) { shop currshop = new shop(); currshop.setShop_id(1L); session.setAttribute("currshop", currshop); shop currshop2 = (com.o2o.shop.entity.shop) session.getAttribute("currshop"); // ... 其他代码 } // insertBatch接口修正 @PostMapping("/insertBatch") @CrossOrigin(allowCredentials = true) @ResponseBody public Map<String,Object> insertBatch(@RequestBody List<productCategory> pcategory, HttpSession session) { Map<String,Object> map = new HashMap<>(); shop currshop2 = (com.o2o.shop.entity.shop) session.getAttribute("currshop"); // 先判空,避免NPE if(currshop2 == null) { map.put("success", false); map.put("msg", "会话失效,请重新获取店铺信息"); return map; } System.out.println("===================="+currshop2.getShop_id()); // ... 其他代码 }
2. 跨域请求未携带凭证
如果前后端是跨域环境,@CrossOrigin默认不允许携带Cookie(包括Session ID对应的JSESSIONID),导致两次请求的Session ID不一致,服务器认为是不同会话。
修复:
- 在
@CrossOrigin注解中添加allowCredentials = true,允许跨域携带凭证 - 前端请求必须开启
withCredentials配置,比如Axios:axios.post('/insertBatch', data, { withCredentials: true })
3. 缺失空指针防护
不管会话是否正常,从Session获取属性后必须先判空再调用方法,直接调用currshop2.getShop_id()必然触发NPE。
修复:
在insertBatch接口中先检查currshop2是否为null,再处理后续逻辑,如上面修正后的代码所示。
验证步骤
- 调用
/getproductlist后,查看浏览器Cookie,确认JSESSIONID已设置 - 调用
/insertBatch时,检查请求头是否携带JSESSIONID Cookie - 在服务器端打印两次请求的
session.getId(),确认是同一个ID,说明是同一会话
内容的提问来源于stack exchange,提问作者Kyle Stan
相关产品推荐
相关产品推荐

