You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,再处理后续逻辑,如上面修正后的代码所示。

验证步骤

  1. 调用/getproductlist后,查看浏览器Cookie,确认JSESSIONID已设置
  2. 调用/insertBatch时,检查请求头是否携带JSESSIONID Cookie
  3. 在服务器端打印两次请求的session.getId(),确认是同一个ID,说明是同一会话

内容的提问来源于stack exchange,提问作者Kyle Stan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 14:24:53