跨域:原因、解决方案CORS、JSONP、proxy、iframe(自用)

一、跨域的根本原因:同源策略

同源策略 ​ 是浏览器最核心的安全基石。它限制了从一个源 加载的文档或脚本如何与另一个源的资源进行交互。

  • 什么是"同源"? ​ 协议、域名、端口三者必须完全相同。

    • 同源:https://www.example.com/page1与 https://www.example.com/page2
    • 不同源:https://www.example.com与 http://www.example.com(协议不同)
    • 不同源:https://www.example.com与 https://api.example.com(域名不同)
    • 不同源:https://www.example.com与 https://www.example.com:8080(端口不同)
  • 限制了什么?

    1. DOM 访问:无法用 JS 读取不同源页面的 DOM、Cookie、LocalStorage 等。
    2. Ajax 请求 :默认情况下,无法用 XMLHttpRequest或 Fetch API向不同源的接口发送请求。
    3. 注意 :链接 <a>、<img>、<script>、<link>等标签的 src或 href属性可以 加载跨域资源,这是跨域资源共享实现的基础。

"跨域"问题的本质是:浏览器限制了脚本发起的跨域 HTTP 请求的响应数据被 JS 代码读取,但请求实际已发出并到达了服务器。

二、解决方案

1. CORS(跨域资源共享)------ 现代标准解决方案

这是 W3C 标准,由服务端通过设置 HTTP 响应头来告诉浏览器允许哪些源、方法、头部进行跨域访问。

  • 简单请求 :满足特定条件(如方法为 GET/POST/HEAD,Content-Type 为 application/x-www-form-urlencoded, multipart/form-data, text/plain)。

    • 浏览器直接发出请求,并在请求头中自动携带 Origin。
    • 服务器响应时,必须在响应头中包含 Access-Control-Allow-Origin: *或 Access-Control-Allow-Origin: https://your-site.com。
  • 预检请求 :不满足简单请求条件(如 Content-Type 为 application/json,或使用了 PUT/DELETE 方法等)。

    1. 浏览器会先自动发送一个 OPTIONS​ 方法的"预检请求"。

    2. 服务器必须响应此预检请求,并返回以下关键头部:

      • Access-Control-Allow-Origin: 允许的源
      • Access-Control-Allow-Methods: 允许的 HTTP 方法
      • Access-Control-Allow-Headers: 允许的自定义请求头
    3. 预检通过后,浏览器才会发送真正的请求。

  • 附带身份凭证的请求:如果请求需要携带 Cookie 或 HTTP 认证信息。

    • 前端:fetch(url, { credentials: 'include' })或 xhr.withCredentials = true
    • 服务器:响应头必须包含 Access-Control-Allow-Credentials: true,并且 Access-Control-Allow-Origin不能为 *,必须是明确的源。

核心:CORS 的关键在于服务器端的配置。

2. JSONP(JSON with Padding)------ 历史方案,用于 GET 请求

利用 <script>标签没有跨域限制的特性来实现。

  • 原理:

    1. 前端定义一个全局回调函数,例如 function handleResponse(data) { ... }。
    2. 动态创建一个 <script>标签,其 src指向目标接口,并携带回调函数名作为参数,如 https://api.other.com/data?callback=handleResponse。
    3. 服务器接收到请求后,将数据作为参数,包裹在回调函数调用中返回,如 handleResponse({"data": 123})。
    4. 浏览器下载并执行此脚本,相当于调用了前端的 handleResponse函数,从而拿到了数据。
  • 缺点:

    • 只支持 GET 请求。
    • 安全性差,容易受到 XSS 攻击。
    • 错误处理机制不完善。

3. 代理服务器(Proxy)------ 开发环境常用

在前后端分离的开发中,为了解决本地开发时的跨域问题,常用代理方案。

  • 原理:由于同源策略是浏览器的限制,服务器之间通信没有此限制。可以设置一个同源的代理服务器,前端将所有请求发给这个代理,由代理转发给目标服务器,再将响应返回给前端。

  • 实现:

    • 开发环境 :使用 Webpack DevServer 的 proxy配置、Vite 的 server.proxy配置,或 Nginx 反向代理。
    • 生产环境 :通常用 Nginx 反向代理,将 /api路径的请求代理到真正的后端服务器。

4. 基于 iframe 的方案(已过时,了解即可)

主要是利用 document.domain降级、window.postMessage或 window.name等技巧在不同源的 iframe 之间传递消息。这些方案较为复杂,安全性有挑战,在现代 CORS 成为标准后已很少使用。

  • document.domain :仅适用于主域相同、子域不同的场景(如 a.example.com和 b.example.com),可同时设置 document.domain = 'example.com'来实现同源。
  • postMessage :HTML5 提供的安全跨源通信方法。一个窗口/iframe 可以向另一个窗口发送消息,目标窗口监听 message事件来接收。

总结与选择

方案 原理 优点 缺点 适用场景
CORS​ 服务端设置响应头 W3C标准,功能强大,支持所有HTTP方法,安全性好 需要服务端配合修改 生产环境首选,前后端分离的标准方案
JSONP​ <script>标签 兼容性极好,支持老浏览器 仅GET,安全性差,错误处理难 需要支持老旧浏览器,且接口仅支持GET的场景(越来越少)
代理​ 服务端转发请求 前端无需修改代码,开发环境无缝切换 生产环境需部署代理服务器,增加架构复杂性 开发环境主流方案,或生产环境用于隐藏真实后端地址、负载均衡
iframe​ 窗口间消息传递 可实现特定复杂场景的跨域通信 实现复杂,安全性需谨慎处理,主方案过时 已逐渐被CORS和postMessage取代,特殊遗留系统兼容

现代 Web 开发的通用实践是:

  • 开发阶段 :使用 Webpack/Vite 代理 或 Nginx 反向代理 来绕过跨域问题。
  • 生产环境 :前后端分离部署,由后端服务正确配置 CORS 响应头 ,或通过 Nginx 反向代理 将 API 请求转发到后端,使前端看起来是在同源下请求。
相关推荐
变与不变8062 小时前
jQuery怎么使用
前端·javascript
神膘护体小月半2 小时前
flex 布局的 order 属性
前端·css
paopaokaka_luck2 小时前
流浪动物救助与收养系统(DeepSeek AI对话、 ECharts多维分析、救助流程衔接、领养与回访衔接、 捐赠确认与公示、志愿者协作)
java·前端·javascript·人工智能·mysql·echarts·推荐算法
仰望.2 小时前
vue 表格组件 vxe-table 树表格懒加载支持拖拽排序的详细用法
前端·javascript·vue.js·vxe-table
前端 贾公子2 小时前
vite-plugin-uni-manifest 升级指南
前端
小码哥_常2 小时前
iPhone 用户传了张 HEIC,我的前端崩了
前端
小码哥_常2 小时前
你发的原图可能暴露你家地址——聊聊图片 EXIF 隐私
前端
java1234_小锋2 小时前
【技术专题】CSS3 网页技术 - CSS3 优先级
前端·css·css3
鸿蒙开发4 小时前
共享 Schema 与 SchemaFactory
前端·后端·harmonyos
屏什么录4 小时前
录屏超过两小时就卡顿崩盘?从参数调优到代码实现,一文彻底搞定长时间录屏
前端·音视频开发