想象一下:你寫了一個網頁 https://www.yoursite.com
,想用 JavaScript 獲取 https://api.othersite.com
的數據。代碼看著沒問題,但瀏覽器無情地拋出一個錯誤:跨域請求被阻止!這就是同源策略(Same-Origin Policy) 在守護安全大門。
一、什么是“源”?—— 你的網絡身份證
瀏覽器的“源”由三塊拼圖組成:
- 協議 (Protocol):
http://
, https://
, ftp://
等 - 域名 (Host):
www.example.com
, api.service.org
等 - 端口 (Port):
:80
(HTTP默認), :443
(HTTPS默認), :8080
等
只有這三者完全相同,才屬于“同源”!
? 同源示例:
https://shop.com/page1
與 https://shop.com/page2
(協議、域名、端口相同)http://localhost:8080/app
與 http://localhost:8080/api
(協議、域名、端口相同)
? 不同源示例:
https://shop.com
vs http://shop.com
(協議不同:HTTPS vs HTTP)https://shop.com
vs https://api.shop.com
(域名不同:shop.com vs api.shop.com)https://shop.com
vs https://shop.com:8443
(端口不同:443 vs 8443)
二、同源策略管什么?—— 瀏覽器的安全圍欄
同源策略的核心目標是:防止惡意網站竊取你的數據或冒充你的身份! 它主要限制以下行為:
讀取非同源 DOM:
- 你的腳本 (
https://your-site.com
) 無法直接讀取或修改 https://bank.com
登錄頁面的 DOM 結構(比如獲取密碼輸入框的值)。想象一下,如果允許,惡意網站就能偷看你在銀行網站的輸入!
發送非同源 AJAX/Fetch 請求 (默認):
- 你的腳本默認不能向
https://api.other-site.com
發送 XMLHttpRequest
或 fetch
請求并讀取響應內容。這是最常見引發跨域錯誤的地方。
讀寫非同源的 Cookie、LocalStorage 等:
- 你網站
https://site-a.com
設置的 Cookie,https://site-b.com
的腳本無法讀取或修改。防止惡意網站盜用你的登錄狀態。
三、安全圍欄的“門縫”—— 允許的跨域加載
同源策略不是鐵板一塊!以下資源默認允許跨域加載(僅加載,JS 通常無法直接操作內容):
<img src="...">
圖片<link rel="stylesheet" href="...">
CSS 樣式表<script src="...">
腳本 (注意:加載的腳本運行在加載它的頁面源下)<iframe src="...">
內嵌框架 (內容可加載,但父頁面 JS 訪問其內容受同源限制)
為什么允許這些?因為它們是構建網頁的基礎資源(圖片、樣式、公共庫),且默認情況下,加載這些資源不會直接暴露敏感數據給加載它們的頁面腳本。
四、實戰跨域問題:AJAX 請求場景
假設你的頁面在 http://localhost:3000
,想請求 http://localhost:4000/api/data
:
fetch('http://localhost:4000/api/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('出錯了:', error));
錯誤信息:
Access to fetch at 'http://localhost:4000/api/data' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
原因:
端口不同 (3000 vs 4000) → 不同源 → 瀏覽器阻止了響應數據的讀取。
五、合法跨域方案:CORS 機制(核心解決方案)
CORS (Cross-Origin Resource Sharing) 是 W3C 標準,是解決跨域問題的官方方案。原理是服務器聲明允許哪些源訪問資源。
關鍵步驟:
- 瀏覽器發送請求: 你的腳本發起跨域請求(如
fetch
)。 - 瀏覽器添加
Origin
頭: 自動帶上當前頁面的源 (e.g., Origin: http://localhost:3000
)。 - 服務器響應: 服務器檢查
Origin
。如果允許該源訪問,則在響應中包含特定 HTTP 頭:Access-Control-Allow-Origin: http://localhost:3000
(或 *
表示允許任何源)- 對于復雜請求(如帶自定義頭或非簡單方法),還需
Access-Control-Allow-Methods
, Access-Control-Allow-Headers
等。
- 瀏覽器放行: 瀏覽器檢查響應頭。如果
Access-Control-Allow-Origin
包含當前源,則允許腳本訪問響應數據。
圖解:

六、其他跨域方案(了解即可)
- JSONP (JSON with Padding): 利用
<script>
標簽不受同源策略限制的特性。只支持 GET 請求,逐漸被 CORS 取代。 - WebSocket: 協議本身支持跨域通信。
- 代理 (Proxy): 讓你的服務器(同源)轉發請求到目標服務器,再將結果返回給你的前端。常用在開發環境解決跨域。
document.domain
(降域): 僅適用于主域相同、子域不同的場景(如 a.example.com
和 b.example.com
),且需要雙方頁面都設置 document.domain = 'example.com'
。限制多,不推薦。
?轉自https://juejin.cn/post/7533457149332176934
該文章在 2025/8/7 17:28:52 編輯過