前端新手也能看懂的跨域問題詳解
在前端開發中,我們經常會聽到“跨域問題”。尤其是在本地調試前端和后臺接口時,瀏覽器突然拋出一堆報錯信息,比如:
Access to XMLHttpRequest at '[http://api.xxx.com/data](http://api.xxx.com/data)' from origin '[http://localhost:8080](http://localhost:8080)' has been blocked by CORS policy...
這到底是什么鬼?別慌,今天我們就一口氣搞清楚什么是跨域、為什么會出現跨域、怎么解決跨域!
一、什么是“跨域”?
跨域指的是:瀏覽器因為安全限制,阻止了網頁對不同源(域名/IP/端口號不同)的請求。
所謂“源”,就是由以下三部分組成的:
- 協議(http/https)
- 域名(或IP)
- 端口號
只要其中任意一項不同,就叫做“不同源”,比如:
地址 | 和 http://localhost:8080 比較 | 是否同源 |
---|---|---|
http://localhost:8080 | 完全相同 | 同源 |
http://localhost:3000 | 端口不同 | 跨域 |
https://localhost:8080 | 協議不同 | 跨域 |
http://127.0.0.1:8080 | IP不同 | 跨域 |
http://api.example.com | 域名不同 | 跨域 |
二、為什么會有跨域限制?
這是瀏覽器的同源策略(Same-Origin Policy)在起作用。
這個策略是為了保護用戶的信息安全,防止惡意網站讀取你在其他網站上的隱私數據(比如你登陸了 A 網站,但正在訪問 B 網站,B 網站偷偷用 JS 請求 A 網站獲取你的個人信息,這就很危險了)。
所以,瀏覽器默認就限制了跨域請求。
三、哪些操作會觸發跨域?
最常見的觸發方式是通過前端的 JavaScript 發送請求,例如:
fetch('http://api.xxx.com/data') // 如果地址和頁面地址不是同源,就會被攔截
其他還有:
- 使用
XMLHttpRequest
或axios
- 頁面內嵌 iframe
- 加載外部的腳本、字體、樣式(但有些資源不受限制)
四、怎么解決跨域問題?
跨域不是不能請求,而是默認不允許。我們可以通過一些方式讓瀏覽器**“信任”**這次跨域請求。
方法一:CORS(跨源資源共享)【推薦】
這是最常見也最官方的方式。
需要后端在響應頭中加上允許跨域的字段:
Access-Control-Allow-Origin: http://localhost:8080
如果允許所有域訪問,也可以寫:
Access-Control-Allow-Origin: *
完整示例(Node.js Express 后端):
app.use((req, res, next) => {res.setHeader('Access-Control-Allow-Origin', '*'); // 允許所有域訪問res.setHeader('Access-Control-Allow-Methods', 'GET,POST'); // 允許的方法res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 允許的請求頭next();
});
方法二:通過代理繞過瀏覽器
在開發環境中,你也可以設置一個本地代理,讓瀏覽器以為你訪問的是同源。
比如用 vite
或 webpack
設置代理:
// vite.config.js
export default {server: {proxy: {'/api': {target: 'http://api.xxx.com',changeOrigin: true,rewrite: path => path.replace(/^\/api/, '')}}}
}
你在前端請求 /api/data
,實際上是請求 http://api.xxx.com/data
,從而繞過跨域限制。
方法三:JSONP(已過時,只支持GET)
是一種早期的跨域方案,用 <script>
標簽加載數據,原理是瀏覽器允許跨域加載 JS 文件。但現在一般不推薦,功能有限,且不支持 POST。
五、總結一句話
跨域問題是瀏覽器安全機制限制的結果,我們可以通過配置 CORS 或使用代理來解決。
FAQ:你可能還想問
-
跨域只在瀏覽器中出現嗎?
是的,Node.js 端、Postman、curl 請求都不會受到“同源策略”的影響。 -
后端一定要支持 CORS 嗎?
如果你要前端直接訪問后端 API,那后端必須支持;否則只能通過代理。 -
是不是所有請求都會被預檢?
不是,簡單請求不會,比如 GET 請求且 Content-Type 是application/x-www-form-urlencoded
。