# 怎么理解Spring Boot跨域
## 一、什么是跨域問題
### 1.1 同源策略的概念
同源策略(Same-Origin Policy)是瀏覽器最核心的安全機制之一,它規定:
- 協議相同(http/https)
- 域名相同(www.example.com)
- 端口相同(8080)
只有三者完全一致才屬于同源,否則就會觸發跨域限制。這是瀏覽器為了防止惡意網站竊取數據而設置的安全屏障。
### 1.2 跨域的表現形式
當出現跨域請求時,瀏覽器控制臺會顯示類似錯誤:
```javascript
Access-Control-Allow-Origin' header is present on the requested resource
常見跨域場景包括: - 前端運行在http://localhost:3000,后端在http://localhost:8080 - 微服務架構中不同子域間的調用(api.service.com調用auth.service.com) - 前后端分離部署時的域名差異
最簡單的局部解決方案,支持方法級和類級配置:
@RestController
@CrossOrigin(origins = "http://example.com") // 類級別
public class MyController {
@GetMapping("/hello")
@CrossOrigin( // 方法級別
origins = "*",
allowedHeaders = "*",
methods = {RequestMethod.GET, RequestMethod.POST}
)
public String hello() {
return "Hello World";
}
}
參數說明:
- origins
:允許的源列表(默認*)
- methods
:允許的HTTP方法
- allowedHeaders
:允許的請求頭
- exposedHeaders
:暴露給客戶端的響應頭
- allowCredentials
:是否允許憑據(cookies等)
推薦的生產環境方案,通過配置類統一管理:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://trusted.com")
.allowedMethods("GET", "POST", "PUT")
.allowCredentials(true)
.maxAge(3600);
}
}
優勢: - 統一管理所有端點的CORS策略 - 支持預檢請求(OPTIONS)緩存 - 可結合Spring Security使用
適用于需要精細控制的場景:
@Component
public class SimpleCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
chain.doFilter(req, res);
}
}
關鍵響應頭:
- Access-Control-Allow-Origin
:允許的源
- Access-Control-Allow-Methods
:允許的方法
- Access-Control-Allow-Headers
:允許的請求頭
- Access-Control-Expose-Headers
:暴露的響應頭
- Access-Control-Allow-Credentials
:是否允許憑據
當項目啟用安全模塊時,需要特殊處理:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> {
CorsConfiguration config = new CorsConfiguration();
config.applyPermitDefaultValues();
config.addAllowedOrigin("https://secure-domain.com");
return config;
});
// 其他安全配置...
}
}
注意事項:
- 必須顯式調用http.cors()
- 默認會禁用allowCredentials
- 需要處理CSRF與CORS的沖突
簡單請求需同時滿足: 1. 使用GET、HEAD或POST方法 2. 僅包含自動設置的頭部(如Accept、Content-Language) 3. Content-Type為:text/plain、multipart/form-data或application/x-www-form-urlencoded
預檢請求(OPTIONS)觸發條件: - 使用PUT、DELETE等非簡單方法 - 包含自定義頭部(如Authorization) - Content-Type為application/json
sequenceDiagram
Browser->>Server: OPTIONS /api (預檢請求)
Server-->>Browser: 返回Allowed-Origin/Methods/Headers
Browser->>Server: GET /api (真實請求)
Server-->>Browser: 數據 + CORS頭
*
:應明確指定可信域名
“`java
// 不安全
.allowedOrigins(”*“)// 安全做法 .allowedOrigins(”https://production.com”, “https://staging.com”)
2. **啟用Credential時嚴格限制源**:
```java
.allowCredentials(true)
.allowedOrigins("https://exact.domain.com") // 不能使用*或通配符
.exposedHeaders("X-Custom-Header", "Content-Disposition")
問題1:配置了CORS但仍報錯 - 檢查是否有多個Filter覆蓋了CORS頭 - 確認Spring Security配置是否正確
問題2:預檢請求返回403 - 確保OPTIONS方法被允許 - 在Spring Security中配置:
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll();
問題3:Cookie無法跨域
- 前端需要設置withCredentials: true
- 后端配置:
.allowCredentials(true)
.allowedOriginPatterns("https://*.domain.com") // 注意使用allowedOriginPatterns而非allowedOrigins
通過Nginx統一域名:
location /api {
proxy_pass http://backend:8080;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
}
傳統跨域方案,已逐漸淘汰:
function handleResponse(data) {
console.log(data);
}
const script = document.createElement('script');
script.src = 'http://other-domain.com/api?callback=handleResponse';
document.body.appendChild(script);
Spring Boot提供了多層次、靈活的跨域解決方案,開發者應根據: - 項目架構復雜度 - 安全要求級別 - 部署環境特點
選擇最適合的方案。對于現代應用,推薦優先采用WebMvcConfigurer
全局配置,配合細致的域名/方法限制,在保證安全的前提下實現跨域資源共享。
關鍵點記憶:
- 開發環境可用*
,生產環境必須指定具體域名
- 帶Credential的請求不能使用通配符
- Spring Security需要單獨配置
- 預檢請求的緩存能提升性能 “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。