Angular5+Spring REST每次请求生成新Session ID问题求助
刚遇到过类似的问题,这在Angular+Spring前后端分离架构里太常见了——本质就是会话Cookie没被正确传递,导致每次请求都触发新的Session。咱们一步步来解决:
一、先搞懂问题根源
Spring的HttpSession是靠浏览器携带的JSESSIONID Cookie来识别会话的,但Angular的HTTP请求默认不会自动带上Cookie;如果是跨域场景(比如Angular跑在localhost:4200,Spring在localhost:8080),浏览器的同源策略还会阻止Cookie跨域传递,双重原因导致每次请求都是新Session。
二、解决方案分步实施
1. 让Angular请求携带Cookie
在Angular的HTTP请求中必须显式设置withCredentials: true,这样才会把浏览器里的Cookie(包括JSESSIONID)随请求一起发送。
方式一:单个请求配置
import { HttpClient } from '@angular/common/http'; constructor(private http: HttpClient) {} loadControls(userId: string) { return this.http.get('/api/controls', { params: { userId }, withCredentials: true // 关键配置:携带Cookie }); }
方式二:全局拦截器统一配置
如果不想每个请求都写一遍,可以用HTTP拦截器全局设置:
// 新建拦截器文件 credential.interceptor.ts import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable() export class CredentialInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler) { // 克隆请求并添加withCredentials配置 const authenticatedReq = req.clone({ withCredentials: true }); return next.handle(authenticatedReq); } }
然后在AppModule里注册这个拦截器:
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { CredentialInterceptor } from './credential.interceptor'; @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: CredentialInterceptor, multi: true // 允许多个拦截器共存 } ] }) export class AppModule {}
2. 配置Spring允许跨域携带凭证
如果你的Angular和Spring不在同一域名/端口,必须在Spring里配置CORS,明确允许携带凭证,并且指定允许的前端来源(不能用*,浏览器不允许通配符搭配凭证)。
方式一:Controller级别的CORS配置
直接在你的接口Controller上添加@CrossOrigin注解:
import org.springframework.web.bind.annotation.CrossOrigin; // 替换成你实际的Angular地址 @CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true") @RequestMapping(value ="/controls" , method= RequestMethod.GET) @ResponseBody public List<InputBase> onLoadResponse( @RequestParam (value = "userId") String inputParam, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, HttpSession session ) { super.responseHeader(httpServletRequest, httpServletResponse); session.setAttribute("root", "root"); return controlService.getControls(...); }
方式二:全局CORS配置
如果有多个接口需要跨域,推荐全局配置:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class GlobalCorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); // 允许携带凭证 config.setAllowCredentials(true); // 指定允许的前端域名(多个的话用addAllowedOrigin逐个添加) config.addAllowedOrigin("http://localhost:4200"); // 允许所有请求头 config.addAllowedHeader("*"); // 允许所有HTTP方法 config.addAllowedMethod("*"); // 对所有接口生效 source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
3. 验证配置是否生效
用浏览器的开发者工具(F12 → Network标签)检查请求:
- 第一次请求后,响应头里应该有
Set-Cookie: JSESSIONID=xxx; Path=/; HttpOnly - 后续请求的Request头里应该有
Cookie: JSESSIONID=xxx
如果能看到这两个头,说明Session已经能正常保持了,你存在session.setAttribute("root", "root")的数据也能在后续请求中获取到。
三、额外注意事项
- 不要在Spring里配置
server.servlet.session.stateless=true,这会禁用Session,直接导致会话无法保持。 - 如果你的Spring应用部署在HTTPS环境下,确保Cookie的
Secure属性正确配置(浏览器只会在HTTPS请求中携带Secure Cookie)。
内容的提问来源于stack exchange,提问作者sahadev
相关产品推荐
相关产品推荐

