一针见血!前端新手也能秒懂浏览器的同源策略
|
freeflydom
2025年8月7日 17:28
本文热度 61
|
想象一下:你写了一个网页 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 编辑过