同源策略
同源(Same Origin):协议、域名、端口三者完全相同。
https://example.com:443/page
https://example.com/api → 同源
http://example.com/api → 不同(协议不同)
https://api.example.com → 不同(域名不同)
https://example.com:8080 → 不同(端口不同)同源策略限制:一个源的脚本不能读取另一个源的资源(如通过 AJAX 读取响应内容)。
目的:防止恶意网站读取你在其它网站的敏感数据。
举例:你登录了银行网站,然后访问了一个恶意站点。如果没有同源策略,恶意站点的脚本就能发起请求到银行网站并读取你的账户信息(因为浏览器会自动带上 cookie)。
同源策略阻止了这种读取。
限制的边界
注意:同源策略限制的是读取响应,不总是限制发送请求。
<img>、<script>、<link>标签可以加载跨域资源(这是 CDN 能工作的基础);- 表单可以提交到跨域地址;
- 但脚本读取跨域 AJAX 的响应内容会被拦截。
这个看似"不一致"的设计,是历史演进和安全权衡的结果。
CORS
CORS(Cross-Origin Resource Sharing,跨域资源共享)是官方的跨域方案:由服务器声明允许哪些源访问。
简单请求
满足特定条件时(如 GET/POST + 特定的 Content-Type),浏览器直接发请求,并在请求头加上:
Origin: https://your-site.com服务器如果允许,在响应头返回:
Access-Control-Allow-Origin: https://your-site.com浏览器看到这个头,就把响应交给 JS。否则拦截。
预检请求(Preflight)
对于"非简单请求"(如 PUT/DELETE、自定义请求头、application/json),浏览器会先发一个 OPTIONS 预检请求:
OPTIONS /api/data
Origin: https://your-site.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type服务器回应允许的源、方法和头:
Access-Control-Allow-Origin: https://your-site.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: content-type
Access-Control-Max-Age: 86400预检通过后,浏览器才发送真正的请求。
Access-Control-Max-Age 让浏览器缓存预检结果,避免每个请求都 OPTIONS 一次。
携带凭证
默认跨域请求不带 cookie。如果需要带上:
- 客户端:
fetch(url, { credentials: 'include' }); - 服务器:
Access-Control-Allow-Credentials: true。
关键限制:当允许凭证时,Access-Control-Allow-Origin 不能是 *,必须是具体的源。
常见错误
一、服务器没配 CORS 头 → 浏览器报 "blocked by CORS policy"。
解决:在服务器端添加相应的响应头(不是前端能解决的——这是服务器端配置)。
二、带 cookie 时用了 * → 报错。
三、代理层的响应头覆盖 → Nginx 等反向代理可能覆盖应用设置的 CORS 头。
其它跨域方案
一、反向代理(开发环境最常用)
让前端开发服务器代理 API 请求,浏览器看到的是同源。
二、JSONP(已过时)
利用 <script> 标签不受同源限制的特性。只支持 GET,且安全性差。现代开发不应再使用。
三、postMessage
用于窗口/iframe 之间的跨域通信。
说明:本文为浏览器安全的知识整理。