基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

解决跨域问题有哪些常见方案?(CORS、JSONP、Nginx反代等)

知识点图片

跨域问题源于浏览器的同源策略(Same-Origin Policy),即协议、域名、端口必须完全一致。

以下是目前最常见、最实用的跨域解决方案,按推荐程度使用场景分类:


一、 主流推荐方案

1. CORS (Cross-Origin Resource Sharing) —— 最标准

这是 W3C 的标准方案,也是目前后端最常用的方式。它允许浏览器向跨源服务器发出 XMLHttpRequest 请求。

  • 原理:后端在响应头中设置 Access-Control-Allow-Origin 等字段,告诉浏览器“我允许这个域名访问我”。
  • 实现
    后端(以 Node.js/Express 为例)设置响应头:
    javascript
    res.header("Access-Control-Allow-Origin", "http://your-frontend-domain.com"); // 或 * (不推荐带Cookie时用*)
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
  • 优点:支持所有 HTTP 请求类型(GET, POST, PUT 等);安全性高。
  • 缺点:需要后端支持;IE9 以下不支持(现在基本可忽略)。
  • 注意:对于复杂请求(如带自定义 Header 或非简单 Content-Type),浏览器会先发送一个 OPTIONS 预检请求。

2. Nginx 反向代理 —— 生产环境最常用

不需要后端改代码,运维在服务器网关层解决。

  • 原理同源策略是浏览器的限制,服务器与服务器之间通信没有跨域限制。
    浏览器访问 Nginx(同源),Nginx 转发请求给后端服务器,再把结果返回给浏览器。
  • 实现
    修改 nginx.conf
    plaintext
    server {
        listen 80;
        server_name www.client.com;
    
        location /api/ {
            # 浏览器访问 http://www.client.com/api/user
            # Nginx 转发给 http://www.server.com/api/user
            proxy_pass http://www.server.com/;
        }
    }
  • 优点:后端无需改动;配置简单;安全性好(隐藏了真实后端地址)。
  • 缺点:需要有 Nginx 服务器配置权限。

3. Node.js 中间件代理 (Webpack/Vite Proxy) —— 开发环境最常用

在 Vue、React 本地开发时,我们经常遇到跨域,这时候不需要后端配合,也不需要装 Nginx。

  • 原理:本地启动了一个 Node.js 服务器(Dev Server),利用 http-proxy-middleware 插件将请求转发给后端。原理同 Nginx。
  • 实现
    • Vue (vue.config.js):
      javascript
      module.exports = {
        devServer: {
          proxy: {
            '/api': {
              target: 'http://www.server.com',
              changeOrigin: true,
              pathRewrite: { '^/api': '' }
            }
          }
        }
      }
    • Vite (vite.config.ts): 类似配置。
  • 注意:这只在本地开发环境生效。打包上线后,通常需要配合 Nginx 反向代理使用。

二、 历史/特定场景方案

4. JSONP (JSON with Padding) —— 经典但过时

  • 原理:利用 <script> 标签没有跨域限制的漏洞。前端定义一个回调函数,通过 script 标签请求后端,后端返回一个函数调用,并将数据作为参数传入。
  • 实现
    • 前端:<script src="http://api.com?callback=handleData"></script>
    • 后端:返回字符串 handleData({ "name": "test" })
  • 优点:兼容性极好(支持老版本 IE)。
  • 缺点只支持 GET 请求;不安全(容易遭受 XSS 攻击);调试困难。
  • 现状:除了老旧系统维护,现代开发基本不再使用。

5. WebSocket

  • 原理:WebSocket 是一种持久化协议。虽然它建立在 TCP 之上,但它本身不受同源策略限制
  • 实现:使用 Socket.io 或原生 WebSocket
  • 注意:虽然浏览器不限制,但后端通常会验证 Origin 头部来防止 CSRF 攻击。

三、 窗口/Iframe 通信方案 (非接口请求)

如果你的跨域需求不是“请求接口”,而是“页面 A 和 iframe 中的页面 B 通信”,则使用以下方案:

6. postMessage

HTML5 引入的 API,专门用于不同窗口(Window)、Iframe 之间的跨域通信。

  • 发送方otherWindow.postMessage(message, targetOrigin)
  • 接收方:监听 message 事件。
    javascript
    window.addEventListener("message", function(event) {
        if (event.origin !== "http://trusted.com") return; // 安全检查
        console.log(event.data);
    });

7. document.domain (仅限主域相同)

  • 场景a.test.comb.test.com
  • 方法:两个页面都设置 document.domain = 'test.com'
  • 现状已废弃。现代浏览器(如 Chrome 115+)默认禁用了修改 document.domain,不推荐使用。

总结:我该用哪个?

  1. 日常开发接口请求
    • 本地开发:使用 Webpack/Vite Proxy
    • 线上部署:使用 Nginx 反向代理
  2. 后端愿意配合:直接用 CORS,这是最标准的方法。
  3. 需要实时通讯:使用 WebSocket
  4. Iframe 通信:使用 postMessage
  5. 必须兼容 IE9 以下且只有 GET 请求:无奈使用 JSONP
00:00
00:00