Skip to content

跨域问题处理详解

更新: 6/6/2026 字数: 0 字 时长: 0 分钟

面向前端 / 全栈开发者的科普向技术文档。本文把"跨域到底是什么、为什么会被拦、有哪些解决办法、各自怎么用"讲清楚,从原理到代码一步到位。


一、什么是跨域:浏览器的"同源策略"

什么是跨域

跨域问题的根源,是浏览器自带的一道安全机制——同源策略。它规定:一个网页只能自由访问"同源"的资源,访问"不同源"的资源会被限制。

什么叫"同源"? 必须满足三者完全一致:协议 + 域名 + 端口

当前页面目标地址是否同源原因
http://a.com/pagehttp://a.com/api✅ 同源三者一致
http://a.comhttps://a.com❌ 跨域协议不同(http vs https)
http://a.comhttp://b.com❌ 跨域域名不同
http://a.com:80http://a.com:8080❌ 跨域端口不同

通俗解释:同源策略就像小区门禁,只有"同一个小区"(同协议+同域名+同端口)的人能自由串门。换个小区(跨域),门口保安就会拦下来。

两个要点必须记住:

  • 跨域是浏览器的限制,目的是防止恶意网站窃取你在其他站点的数据,是一种安全保护。
  • 服务器之间没有跨域问题。跨域只发生在"浏览器→服务器"这条链路上;服务器去请求另一台服务器,畅通无阻。这也是后面很多解决方案的底层逻辑——让请求绕到服务器之间去完成

二、六种跨域解决方案总览

六种解决方案

解决跨域的常见方法有六种,各有适用场景:

方法核心思路适用场景
① 开发环境代理(Vite proxy / Webpack devServer)本地开发服务器代为转发请求仅开发环境调试
② Nginx 代理用 Nginx 的 location 把请求转到后端生产环境,运维侧统一处理
③ CORS后端加 Access-Control-Allow-Origin 响应头,指定允许的源生产环境主流方案
④ WebSocketWebSocket 协议本身不受同源策略限制需双向实时通信(需服务器支持)
⑤ SSE(服务器推送事件)服务器单向推数据给客户端,不受同源限制服务器→客户端的单向推送
⑥ JSONP<script> 标签可加载任意域资源的特性绕过限制老项目兼容,仅支持 GET

简单归类:①②是"代理/转发"思路,把跨域问题交给服务器解决;是"官方授权"思路,由后端明确放行;④⑤⑥则是利用了某些天生不受同源策略约束的协议或标签。下面重点讲最常用的几种。


三、开发环境代理:Vite 与 Webpack

开发环境代理

开发阶段,Vite 和 Webpack 都内置了代理功能。原理是:前端不直接请求后端 API,而是先请求本地开发服务器,再由它把请求转发给后端。因为"服务器到服务器"没有跨域问题,所以这条路就通了。

Vite 代理配置

Vite 在 vite.config.jsserver.proxy 里配置:

javascript
// vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'http://backend.example.com', // 目标后端服务器地址
        changeOrigin: true,                    // 改写请求的 origin,使其像同源请求
        rewrite: path => path.replace(/^\/api/, '') // 重写路径,去掉 /api 前缀
      }
    }
  }
}

效果:所有以 /api 开头的请求都会被代理到 http://backend.example.com,并自动改写 origin。

Webpack 代理配置

Webpack 借助 webpack-dev-server 的代理功能,在 webpack.config.js(或单独的 dev-server 配置)里写:

javascript
// webpack.config.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://backend.example.com',
        secure: false,                 // 目标为 HTTPS 时按需设置
        changeOrigin: true,
        pathRewrite: { '^/api': '' }   // 重写路径,去掉前缀
      }
    }
  }
});

注意事项

  1. 确保 target 后端地址正确无误。
  2. changeOrigin: true 让请求的 origin 被改写成目标地址,以便后端正确识别、允许跨域。
  3. rewrite / pathRewrite 用于去掉代理前缀(如 /api),保证后端能正确解析真实路径。

关键提醒:代理只在本地开发环境生效。打包上线后这套配置就不起作用了——生产环境的跨域要靠 Nginx 或 CORS 解决。


四、生产环境主力:CORS 与 Nginx 代理

CORS 与 Nginx

CORS:后端"官方授权"放行

CORS(跨域资源共享)是生产环境最主流的方案。 思路很直接:由后端在响应里加上一个特殊的 HTTP 头 Access-Control-Allow-Origin,明确告诉浏览器"哪些源被允许访问我"。浏览器看到这个头,确认当前页面在允许名单里,就放行。

text
# 后端响应头示例
Access-Control-Allow-Origin: https://www.frontend.com   # 只允许这个源
# 或允许所有源(不建议用于带凭证的接口)
Access-Control-Allow-Origin: *

通俗解释:CORS 就像服务器给浏览器递了一张"通行证",上面写明"我允许 frontend.com 来访问"。浏览器验证通行证后才放行。它需要后端配合修改响应头,前端无需特殊处理。

Nginx 代理:同域名下统一转发

Nginx 方案利用了反向代理。把前端页面和后端接口都挂在同一个域名下,用 Nginx 的 location 规则把不同路径的请求分发到对应后端。这样在浏览器看来,请求始终是"同源"的,自然就不存在跨域:

nginx
server {
    listen 80;
    server_name www.example.com;

    # 前端静态页面
    location / {
        root /var/www/frontend;
        index index.html;
    }

    # 以 /api 开头的请求,转发给后端服务器
    location /api/ {
        proxy_pass http://backend.example.com/;
    }
}

通俗解释:浏览器只跟 www.example.com 打交道(同源),至于 /api 的请求 Nginx 在背后转给了谁,浏览器并不关心——跨域问题被"藏"到了服务器之间。


五、JSONP:借 <script> 标签绕过限制

JSONP 原理

JSONP(JSON with Padding) 是一种较老的跨域技术。它的巧妙之处在于:<script> 标签天生可以加载任意域名的资源(不受同源策略限制),JSONP 正是钻了这个空子。它需要前后端互相配合才能完成。

工作流程

  1. 客户端定义回调函数:先写一个函数,用来处理服务器返回的数据。
  2. 构建请求 URL:在 URL 里带上一个参数,告诉服务器回调函数的名字(如 callback=handleResponse)。
  3. 动态插入 <script> 标签:把 src 设为这个 URL,发起请求。
  4. 服务器响应:服务器把数据包装成一段"函数调用"的 JS 代码返回,函数名就是请求里指定的那个。
  5. 执行回调<script> 加载完成后,浏览器执行这段 JS,也就是调用了你的回调函数,数据随之被处理。

客户端代码

javascript
// ① 定义回调函数
function handleResponse(data) {
  console.log('收到数据:', data);
}

// ② 动态插入 script,URL 里带上回调函数名
var script = document.createElement('script');
script.src = 'http://example.com/data?callback=handleResponse';
document.head.appendChild(script);

服务器返回的内容(注意:返回的不是纯 JSON,而是一段函数调用):

javascript
handleResponse({ "key": "value" });

这样,即使 http://example.com 与当前页面不同源,也能成功拿到并处理数据。

重要限制:JSONP 只支持 GET 请求(因为它靠 <script src> 发起,无法发 POST);且因为是执行远端返回的脚本,存在安全风险,只信任可靠的接口。如今它基本被 CORS 取代,主要用于兼容老项目。


一页速记

  • 跨域根源:浏览器同源策略——协议+域名+端口必须三者一致,否则被拦;服务器之间无跨域
  • 开发环境:Vite server.proxy / Webpack devServer.proxy 本地代理转发,仅开发时生效。
  • 生产环境CORS(后端加 Access-Control-Allow-Origin 放行,最主流)+ Nginx 同域名反向代理。
  • 特殊协议:WebSocket(双向)、SSE(单向推送)天生不受同源限制。
  • JSONP:借 <script> 绕过限制,仅支持 GET,需前后端配合,现多用于兼容老项目。