跨域
浏览器为了安全而限制不同源(协议、域名、端口任一不同)的脚本访问资源(如 Cookie、DOM、AJAX)。
- 保护 DOM 安全:禁止不同源的页面操作当前页面的 DOM,比如防止恶意网站通过 iframe 嵌套网页并篡改内容
- 保护 Cookie 安全:禁止不同源的页面读取当前页面的 Cookie(Cookie 中常储存登录状态、用于信息等敏感数据),避免身份被盗用
- 保护数据安全:禁止不同源的脚本发起请求获取当前网络的敏感数据(比如说订单、个人信息),防止数据泄漏
一、 常见的跨域场景
Ajax请求:使用XMLHttpRequest或fetch等 API 发送跨域请求- 第三方服务集成:集成地图、支付服务等第三方资源
- 单点登录:多个应用之间共享用户认证信息
iframe嵌入内容:父页面与 Iframe 之间的交互- Web 字体:加载不同域的字体
Canvas加载图片:在Canvas中绘制不同源的图像- WebGL 贴图:在 WebGL 中使用贴图也会像在 Canvas 中绘制图片一样有同源限制
- 来自图像的 CSS 图形:
二、 跨域解决方案
跨域问题需要前端和后端配合解决解决
- CORS(跨资源共享)
- JSONP (兼容方案,仅支持 GET)
- 开发环境使用代理服务器
1. CORS (跨资源共享)
官方推荐,通过服务器设置相应头授权允许固定源跨域。
- 简单请求
- 方法:GET、POST、HEAD
- 头部:仅允许简单头部(如
Content-Type: application/x-www-form-urlencoded) - 流程:直接发送请求,服务器返回
Access-Control-Allow-Origin: <允许的源>(如*或具体的域名)即可
- 非简单请求(如 PUT、带自定义头部)
- 先发送 预检请求(OPTIONS),询问服务器是否允许跨域(包含方法、头部等信息)
- 服务器返回
Access-Control-Allow-Methods、Access-Control-Allow-Headers等授权后,再发送实际请求
关键相应头:
-
Access-Control-Allow-Origin:允许的源(如*或https://example.com) -
Access-Control-Allow-Methods:允许的 HTTPS 方法(如GET、POST) -
Access-Control-Allow-Headers:允许的请求 -
Access-Control-Expose-Headers:允许前端访问的额外相应头 -
优点:标准的 W3C 方案,安全性高,支持所有的请求方法
-
缺点:需要后台配合修改代码
2. 代理服务器
前端请求发送到本地开发服务器,由代理服务器转发到目标服务器
-
开发服务器:
Vue CLI、Vite等配置代理 -
生产环境:Nginx 反向代理
-
优点:无需服务器支持 CORS,配置简单
-
缺点:仅适用于开发环境(生产环境需要服务器配合配置)
3. JSONP
利用 <script> 标签不受同源策略的影响的特性
- 客户端定义回调函数(如
handleData(data)) - 动态创建
<script scr="https://跨域域名/api?callback=handleData"> - 服务器返回
handleData(响应数据),客户端通过回调函数接收数据
- 仅支持 GET
- 安全性低,无错误处理,且存在 XSS 风险
- 无法获取相应头和状态码
4. postMessage
HTML5 提供的跨域通信 API,通过 postMessage() 方法进行不同源页面之间的通信。
-
A 页面向 B 页面发送消息:
iframe.contentWindow.postMessage(data, '*') -
B 页面监听消息:
window.addEventListener('message', callback) -
优点:安全、灵活、支持所有的浏览器
-
缺点:需要双方页面都进行相应的处理
5. document.domain + iframe
通过设置同一主域下不同子域的 document.domain 为相同的源,即可完成跨域。
- 优点:无需后端配合
- 缺点:仅适用于同一主域,不支持跨主域
6. WebSocket -- 全双工跨域通信
webSocket 是独立于 HTTP 协议( ws:// 或 wss://),建立连接后浏览区域服务器可全双工通信,且不受同源策略的限制。适用于实时聊天的通信场景。
- 优点:实时性强,全双工通信,不受同源限制
- 缺点:需后端支持 WebSocket 协议,不适合简单的 HTTP 请求的场景