同源&跨域
🔒 同源策略(Same-Origin Policy)
浏览器的安全机制,限制 JS 对不同源资源的访问。判断是否同源需满足:协议、域名、端口号相同。
示例:
页面地址 | 资源地址 | 是否同源 | 🚨原因 |
---|---|---|---|
http://a.com:80 |
http://a.com:80 |
✅ | 完全相同 |
http://a.com |
https://a.com |
❌ | 协议不同 |
http://a.com |
http://b.com |
❌ | 域名不同 |
http://a.com:80 |
http://a.com:8080 |
❌ | 端口不同 |
🚫 哪些操作会被限制?
- JS 发起的
fetch
/XMLHttpRequest
跨域请求 - 访问
localStorage
、cookie
等数据 - iframe 跨域访问父/子页面 DOM
🌐 什么是跨域?
浏览器阻止你访问不同源资源时,就发生了跨域。
非同源访问资源(如 Ajax 请求)默认会被浏览器拦截。
简单请求与复杂请求
浏览器把跨域请求分为两类:
✅ 简单请求(不会发送预检)
同时满足以下三个条件:
- 方法是
GET
、POST
或HEAD
- 请求头 仅限于:
Accept
、Accept-Language
、Content-Type
(值仅限于:application/x-www-form-urlencoded
、multipart/form-data
、text/plain
) - 没有自定义请求头
⚠️ 复杂请求(会先发送预检 OPTIONS 请求)
只要满足以下任意一项,就属于复杂请求:
- 方法为
PUT
、DELETE
等非 GET/POST/HEAD - 请求头中有自定义 Header(如
X-Token
) Content-Type
为application/json
等非简单类型- 使用了
XMLHttpRequest.withCredentials = true
(携带 cookie)
🔁 流程:
- 浏览器先发
OPTIONS
请求询问服务器是否允许 - 服务器返回
Access-Control-Allow-*
系列响应头,表示允许 - 浏览器才会发起真正的请求
⛔ 若预检失败(服务器未正确设置允许跨域),正式请求不会被发送
🔁 预检请求长这样(由浏览器自动发出):
1 | httpCopyEditOPTIONS /user HTTP/1.1 |
服务端响应应如下:
1 | httpCopyEditHTTP/1.1 204 No Content |
✅ CORS:主流跨域解决方案
服务端返回特殊响应头,告诉浏览器“我允许你跨域访问”:
示例:
1 | Access-Control-Allow-Origin: https://your-frontend.com |
通配符允许所有:
1 | Access-Control-Allow-Origin: * |
🧪 跨域开发常见解决方案
方式 | 说明 |
---|---|
✅ CORS | 服务端设置响应头(最推荐) |
🌀 代理转发 | 本地开发用 webpack devServer 或 Nginx 转发 |
📜 JSONP | 只支持 GET,已过时 |
📨 postMessage | iframe/窗口间通信方案 |