1 什么是跨域問題?
很多小伙伴第一次遇到跨域問題,大概率會一臉懵逼:“我后端接口明明通了,Postman也能調,為啥瀏覽器就報紅字?”

其實這事兒得怪瀏覽器的“同源策略”(Same-Origin Policy)。
簡單說,瀏覽器覺得“不同源的請求都是耍流氓”。
比如你的前端跑在http://localhost:8080。
而后端在https://api.xxx.com:8000。
只要協議
、域名
、端口
任何一個不同,就會被瀏覽器直接掐斷。
舉個栗子??:
fetch('http://api.xxx.com:8000/user')
.then(res => res.json())
.then(data => console.log(data));
這時候,你就需要“跨域解決方案”來幫瀏覽器松綁了!
那么,如何解決跨域問題呢?
2 解決跨域問題的方案
2.1 CORS(跨域資源共享)
適用場景:前后端分離項目、接口需要兼容多種客戶端。
CORS是W3C標準,后端只需在響應頭里加幾個字段,告訴瀏覽器“這個接口我允許誰訪問”。
后端代碼示例(Spring Boot版):
@CrossOrigin(origins = "http://localhost:8080")
@GetMapping("/user")
public User getUser() { ... }
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
關鍵響應頭:
- Access-Control-Allow-Origin: http://localhost:8080(允許的源)
- Access-Control-Allow-Methods: GET,POST(允許的方法)
- Access-Control-Allow-Credentials: true(允許帶Cookie)
注意坑點:
- 如果用了
allowCredentials(true)
,allowedOrigins
不能為*
(必須明確指定域名)。 - 復雜請求(比如Content-Type是
application/json
)會先發一個OPTIONS預檢請求,記得處理!
2.2 JSONP
適用場景:老項目兼容、只支持GET請求(比如調用第三方地圖API)。
JSONP利用<script>
標簽沒有跨域限制的特性,讓后端返回一段JS代碼。
前端代碼:
function handleUserData(data) {
console.log("收到數據:", data);
}
const script = document.createElement('script');
script.src = 'http://api.xxx.com:8000/user?callback=handleUserData';
document.body.appendChild(script);
后端代碼:
@GetMapping("/user")
public String jsonp(@RequestParam String callback) {
User user = new User("Tony", 30);
return callback + "(" + new Gson().toJson(user) + ")";
}
輸出結果:
handleUserData({"name":"Tony","age":30})
缺點:
- 只支持GET(傳參長度有限)。
- 容易被XSS攻擊(畢竟得信任第三方腳本)。
2.3 Nginx反向代理
適用場景:生產環境部署、微服務網關統一處理。
直接把跨域問題甩給Nginx,讓瀏覽器以為所有請求都是同源的。
Nginx配置示例:
server {
listen 80;
server_name localhost;
location /api {
proxy_pass http://api.xxx.com:8000;
add_header 'Access-Control-Allow-Origin' 'http://localhost:8080';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
}
}
此時前端請求地址改成同源:
fetch('/api/user')
優點:
- 前后端代碼零侵入。
- 能隱藏真實接口地址(安全加分)。
2.4 網關層統一處理
適用場景:Spring Cloud Gateway、Kong等API網關。
和Nginx思路類似,但更適合微服務場景,直接在網關層加CORS配置。
Spring Cloud Gateway配置:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "http://localhost:8080"
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true
2.5 WebSocket
適用場景:實時通信需求(聊天室、股票行情)。
WebSocket協議沒有跨域限制(因為握手階段走HTTP,后續升級為長連接)。
前端代碼:
const socket = new WebSocket('ws://api.xxx.com:8000/ws');
socket.onmessage = (event) => {
console.log('收到消息:', event.data);
};
后端代碼(Spring Boot):
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyWebSocketHandler(), "/ws");
}
}
2.6 PostMessage
適用場景:頁面與iframe、彈窗之間的跨域通信。
通過window.postMessage
實現不同窗口間的數據傳遞。
父頁面(http://parent.com):
const childWindow = window.open('http://child.com');
childWindow.postMessage('我是張三', 'http://child.com');
子頁面(http://child.com):
window.addEventListener('message', (event) => {
if (event.origin !== 'http://parent.com') return;
console.log('收到張三的消息:', event.data);
});
總結
- 簡單粗暴:開發環境用CORS注解。
- 生產環境:優先Nginx/網關統一處理,避免每個服務配一遍。
- 老項目兼容:JSONP勉強能用,但別長期依賴。
- 實時場景:直接上WebSocket,順便解決通信問題。
- 安全第一:
Access-Control-Allow-Origin
盡量別寫*
,白名單要用精確域名。
最后提醒溫馨提醒一下:跨域問題本質是瀏覽器行為,和HTTP協議無關。
如果你用Postman,發送curl請求,測試沒問題,但瀏覽器報錯,別懷疑人生,這可能是前端的鍋!
轉自https://www.cnblogs.com/12lisu/p/18744568?
該文章在 2025/3/3 8:55:39 編輯過