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

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

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

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

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

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

"跨域"问题的本质是:浏览器限制了脚本发起的跨域 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.postMessagewindow.name等技巧在不同源的 iframe 之间传递消息。这些方案较为复杂,安全性有挑战,在现代 CORS 成为标准后已很少使用。

  • document.domain :仅适用于主域相同、子域不同的场景(如 a.example.comb.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 请求转发到后端,使前端看起来是在同源下请求。
相关推荐
Setsuna_F_Seiei3 小时前
前端转型 Agent 开发 04 之 MCP 与 Skill(赋予 Agent 更广工作能力)
前端·agent
刘发财4 小时前
前端2秒生成500页矢量PDF,rust真的强到没朋友
前端·javascript·rust
郑州光合科技余经理5 小时前
国际版外卖系统:税率字段怎么和订单主流程解耦
android·java·开发语言·前端·后端·php·ai编程
梦想平凡5 小时前
百游棋牌源代码开发搭建教程(十):隔离部署、备份恢复与双端验收
java·前端·javascript·数据库·源代码管理
yume_sibai6 小时前
06-Rust Web 开发实战(Axum 框架 + 数据库 + JWT 认证 + 中间件 + 部署)
前端·数据库·rust
计算机魔术师8 小时前
特朗普上台打给黄仁勋:AI末日论是骗局,我们绝不让它发生
前端
troy1288 小时前
Python 基础语法(八):Web 后端开发、数据分析与可视化、网络爬虫、人工智能 / 大模型应用
前端·python·数据分析
计算机魔术师8 小时前
CEO说要慢下来,黑客说别做梦了——同一篇论文,两种命运
前端
kyriewen9 小时前
我花3天抓了一个幽灵bug,凶手藏在第4层
前端·javascript·程序员
IT_陈寒9 小时前
Java里用Stream.parallel()翻车实录,这性能还不如单线程
前端·人工智能·后端