什么是同源策略?
同源策略是浏览器自带的安全机制,目的:防止一个网站随便读取 / 操作另一个网站的数据。
它限制:从源 A 加载的脚本,不能默认访问源 B 的资源。
什么叫「同源」?
协议 + 域名 + 端口 三者完全一样,才叫同源。
只要有一个不一样,就是跨域。
示例:当前页面:http://www.example.com:8080/a.html
| 对比 URL | 是否同源 | 原因 |
|---|---|---|
| http://www.example.com:8080/b.html | ✅ 同源 | 完全一样 |
| https://www.example.com:8080/a.html | ❌ 跨域 | 协议不同(http vs https) |
| http://api.example.com:8080/a.html | ❌ 跨域 | 域名不同 |
| http://www.example.com:9090/a.html | ❌ 跨域 | 端口不同 |
| http://www.example.com/a.html | ❌ 跨域 | 端口不同(8080 vs 默认 80) |
同源策略到底限制什么?
浏览器只限制 JS 行为,不限制资源加载。
1. 被限制的行为
- 无法通过 AJAX / fetch 读取跨域接口的响应
- 无法读取另一个域的 Cookie、LocalStorage、SessionStorage
- 无法获取另一个域的 DOM 内容
- 无法获取另一个域的 IndexedDB 数据
2. 不被限制的行为
这些可以跨域加载,因为只是资源引用,不涉及数据窃取:
<img src="跨域图片"><link href="跨域CSS"><script src="跨域JS">
为什么要有同源策略?
一句话:防止你的账号被盗、数据被偷、操作被伪造。
举个真实危险场景:
- 你登录了 bank.com(银行),Cookie 存在浏览器
- 你打开了恶意网站 evil.com
- 如果没有同源策略:
- evil.com 的 JS 可以直接读取 bank.com 的 Cookie
- 可以直接调用 bank.com 的转账接口
- 直接把你的钱转走
同源策略就是堵死这种可能。
同源策略 vs CORS 关系(你最关心的)
同源策略:
是规则,是限制本身。
默认不让你跨域。
CORS(跨域资源共享):
是官方允许的 “合法通行证”。
服务器通过返回响应头:Access-Control-Allow-Origin: https://你的前端域名
告诉浏览器:这个跨域请求是我允许的,放行。
浏览器处理跨域请求流程
发起请求
↓
判断:是不是跨域请求?
├─── 否(同源)→ 直接放行,无任何限制
↓
是(跨域)
↓
判断:是不是 简单请求?
├─── 是 → 走【事后校验】
└─── 否 → 走【事前校验(预检 OPTIONS)】
简单请求 → 事后校验(先发请求,后检查)
1. 什么是简单请求?
同时满足 3 条:
- 方法只能是:GET / HEAD / POST
- 请求头只有这些:
- Accept
- Accept-Language
- Content-Language
- Content-Type 只能是:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
2. 简单请求执行流程
浏览器直接发送真实请求
↓
服务器执行并返回响应
↓
浏览器检查响应头:
有无 Access-Control-Allow-Origin
├─── 有且匹配 → 把数据给 JS
└─── 没有/不匹配 → 拦截响应,JS 拿不到数据
关键点:
请求已经发了,服务器已经执行了,浏览器只是拦结果。
非简单请求 → 事前校验(预检 OPTIONS)
1. 什么是非简单请求?
满足任意一条就是:
- 方法:PUT / DELETE / PATCH
- 自定义头:Token / Authorization / X-XXX
- Content-Type: application/json
2. 非简单请求执行流程
浏览器先发 OPTIONS 预检请求
↓
服务器检查:
允许的方法、允许的头、允许的源
├─── 预检不通过 → 真实请求不发送
↓
预检通过
↓
浏览器缓存预检结果(Access-Control-Max-Age)
↓
发送真实请求
↓
正常返回数据
关键点:
预检不过 → 真实请求永远不发,服务器完全不执行。
为什么要分 “事前 / 事后”?
简单请求(事后)
为了兼容历史老服务器不认识 OPTIONS,不能乱加预检。
非简单请求(事前)
为了安全防止跨域直接改数据、删数据。
CORS 必须懂的 4 个头
- Access-Control-Allow-Origin 允许哪个源(必填)
- Access-Control-Allow-Methods 允许哪些方法(预检用)
- Access-Control-Allow-Headers 允许哪些头(预检用)
- Access-Control-Max-Age 预检缓存时间(秒)
下一篇 →离线语音合成
