跨域请求携带Cookie方案咨询:Spring MVC+Angular4跨端口通信问题
这种跨域带Session Cookie的场景我之前在开发前后端分离项目时也踩过坑,完全不用把Angular项目塞进Spring的src/main/webapp目录里,只要前后端分别配置CORS(跨域资源共享)规则就能完美解决,给你详细的步骤和示例:
一、后端Spring MVC配置(核心)
要让后端允许前端跨域请求并接受凭证(Cookie),有两种配置方式,推荐全局配置避免重复代码:
1. 全局CORS配置类
创建一个配置类实现WebMvcConfigurer,重写addCorsMappings方法,明确允许前端源、允许携带凭证:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class GlobalCorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 对所有接口生效 .allowedOrigins("http://localhost:4200") // 只能是你的前端地址,不能用*(带凭证时浏览器不允许通配符) .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许所有常用请求方法 .allowedHeaders("*") // 允许所有请求头 .allowCredentials(true) // 关键:允许携带Cookie等凭证 .maxAge(3600); // 预检请求的缓存时间,减少OPTIONS请求次数 } }
2. 如果你用了Spring Security
如果项目集成了Spring Security,还要额外配置允许OPTIONS预检请求通过,否则会被拦截:
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.http.HttpMethod; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors() // 启用上面配置的CORS规则 .and() .authorizeRequests() // 其他安全规则(比如允许匿名访问登录接口) .antMatchers("/api/login").permitAll() .anyRequest().authenticated() // 允许OPTIONS预检请求通过 .and().authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll(); } }
二、前端Angular4配置
前端需要明确告诉HTTP请求要携带凭证,同样有两种方式:
1. 单个请求配置
在发起POST请求时,设置withCredentials: true:
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable() export class ApiService { constructor(private http: HttpClient) {} submitUserInfo(data: any) { const apiUrl = 'http://localhost:8080/api/user/submit'; // 关键:添加withCredentials选项 return this.http.post(apiUrl, data, { withCredentials: true }); } }
2. 全局配置(推荐)
如果所有请求都需要携带Cookie,可以通过HTTP拦截器全局设置,避免每个请求重复写:
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http'; @Injectable() export class CredentialsInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler) { // 克隆请求并添加withCredentials属性 const authReq = req.clone({ withCredentials: true }); return next.handle(authReq); } }
然后在AppModule的providers数组中注册拦截器:
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; @NgModule({ imports: [HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: CredentialsInterceptor, multi: true } ] }) export class AppModule {}
三、关键注意事项
- 后端
allowedOrigins不能设为*:当allowCredentials=true时,浏览器禁止使用通配符,必须指定具体的前端域名/地址 - 前端
withCredentials必须设为true:否则浏览器不会主动携带Cookie - Session Cookie的
SameSite属性:本地开发HTTP环境下可以设为Lax(默认可能就是),如果是生产HTTPS环境,跨域场景下需要设为None并配合Secure属性(确保Cookie仅在HTTPS下传输)
至于你提到的JSONP方案,确实不适合你的场景——它只能支持GET请求,无法处理POST,而且安全性和扩展性都远不如CORS,也会给后续e2e测试带来不必要的麻烦,所以CORS是最优解。
内容的提问来源于stack exchange,提问作者Achref Gassoumi
相关产品推荐
相关产品推荐

