浏览器跨域问题CORS完整解决方案指南目录前言一、跨域是如何产生的二、方案全景图三、方案详解方案一CORS 响应头标准方案方案二JSONP已过时方案三Nginx 反向代理 ⭐生产最常用方案四开发服务器代理Vite / Webpack Dev Server方案五自建代理服务自托管 Agent方案六第三方云代理方案七浏览器扩展方案八关闭浏览器安全策略方案九Electron / 桌面端应用四、方案选型决策树五、总结前言跨域问题是 Web 开发中最常见的痛点之一。当浏览器发出一个不同源协议、域名、端口任一不同的请求时同源策略Same-Origin Policy会起作用阻止页面读取跨域返回的数据。这不是 Bug而是浏览器的安全机制。本篇文章从实践出发结合真实项目中一个数据产品 API 测试工具的处理经验系统梳理所有可行的 CORS 解决方案及其适用场景。一、跨域是如何产生的一个请求是否跨域看以下三者是否一致维度示例协议http://vshttps://域名localhostvsapi.example.com端口:8080vs:443只要有一个不同就是跨域请求。浏览器会简单请求在请求头中加Origin检查响应头Access-Control-Allow-Origin非简单请求含自定义头、非 GET/POST、带content-type: application/json等先发一次OPTIONS预检请求Preflight通过后才发真实请求注意跨域请求实际上已经到达了服务器并成功返回是浏览器拦截了响应不让 JavaScript 读取。这是理解所有解决方案的关键前提。二、方案全景图问题浏览器 → 不同源服务器 → 被拦截 ❌ 解决方案分类 ├── 后端配合类需要修改目标服务器 │ ├── 方案1CORS 响应头标准方案 │ └── 方案2JSONP仅限 GET已过时 │ ├── 代理转发类不需改目标服务器 │ ├── 方案3Nginx 反向代理 ⭐生产最常用 │ ├── 方案4开发服务器代理Vite / Webpack Dev Server │ ├── 方案5自建代理服务自托管 Agent │ └── 方案6第三方云代理 │ ├── 开发调试类 │ ├── 方案7浏览器扩展 │ └── 方案8关闭浏览器安全策略 │ └── 环境绕行类 └── 方案9Electron / 桌面端无同源限制下面逐一详解。三、方案详解方案一CORS 响应头标准方案原理目标服务器在响应中添加特定的 HTTP 头告诉浏览器「允许这个来源访问」。服务器需要配置的响应头Access-Control-Allow-Origin: https://your-frontend.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization, X-Custom-Header Access-Control-Allow-Credentials: true Access-Control-Max-Age: 86400Nginx 配置示例location /api/ { add_header Access-Control-Allow-Origin https://your-frontend.com; add_header Access-Control-Allow-Methods GET, POST, OPTIONS; add_header Access-Control-Allow-Headers Content-Type, Authorization; if ($request_method OPTIONS) { return 204; } }Spring Boot 配置示例ConfigurationpublicclassCorsConfig{BeanpublicWebMvcConfigurercorsConfigurer(){returnnewWebMvcConfigurer(){OverridepublicvoidaddCorsMappings(CorsRegistryregistry){registry.addMapping(/api/**).allowedOrigins(https://your-frontend.com).allowedMethods(GET,POST,PUT,DELETE).allowedHeaders(*).allowCredentials(true);}};}}优点标准方案浏览器原生支持无需额外服务/组件缺点需要修改目标服务器携 Cookie 时allowedOrigins不能是*适用场景你能控制后端服务器。方案二JSONP已过时利用script标签不受同源策略限制的特点通过动态创建 script 标签加载数据。缺点只支持 GET 请求存在安全风险XSS无法处理错误状态码不推荐在新项目中使用仅作了解。方案三Nginx 反向代理 ⭐生产最常用原理让所有请求看起来都是从同一源发出的——前端请求同源的代理路径Nginx 在服务端转发到真实目标。架构浏览器http://your-frontend.com ↓ 同源请求 /api/xxx Nginx ↓ 服务端转发无 CORS 限制 目标服务器https://api-target.com/xxx配置示例server { listen 80; server_name your-frontend.com; # 前端静态文件 root /usr/share/nginx/html; # API 代理 location /api/ { proxy_pass https://api-target.com/; proxy_set_header Host api-target.com; proxy_set_header X-Real-IP $remote_addr; # 超时配置 proxy_read_timeout 60s; proxy_connect_timeout 60s; } }多环境代理示例来自真实项目location /data-api/sit01/ { proxy_pass https://api-sit01.example.com/easy-data-api/; proxy_set_header Host api-sit01.example.com; } location /data-api/uat/ { proxy_pass https://api-uat.example.com/; proxy_set_header Host api-uat.example.com; }前端代码无需任何跨域处理直接请求同源路径// 不需要 CORS因为这是同源请求constresponseawaitfetch(/api/user/list,{method:POST,headers:{Content-Type:application/json},body:JSON.stringify({name:test})});如果是 Vite / Webpack 开发环境同样配置反向代理// vite.config.jsexportdefaultdefineConfig({server:{proxy:{/api:{target:https://api-target.com,changeOrigin:true,rewrite:(path)path.replace(/^\/api/,)}}}});优点不需要后端配合修改生产环境标准实践可以统一做鉴权、限流、日志缺点多维护一层代理配置新增环境需要修改 Nginx 配置适用场景几乎所有生产 Web 应用——这是目前最主流的方案。方案四开发服务器代理Vite / Webpack Dev Server原理同上只是运行在开发阶段的 Node.js 服务器中。是开发阶段的标配方案。// vite.config.jsexportdefaultdefineConfig({server:{port:8080,proxy:{/api/v1/pamir/farseer:{target:https://farseer-sit01.example.com,changeOrigin:true,secure:true},/data-api/sit01:{target:https://api-sit01.example.com/easy-data-api,changeOrigin:true,rewrite:(path)path.replace(/^\/data-api\/sit01/,)}}}});方案五自建代理服务自托管 Agent这是 Apifox 网页版等 API 测试工具的解决方案之一。原理在自己服务器上部署一个轻量级的代理服务通常 Docker 化浏览器将目标 URL 作为参数发给这个代理服务代理在服务端发起请求绕过 CORS。架构浏览器Apifox 网页 │ fetch(https://my-agent-server/proxy?urlhttps://api-target.com/xxx) ▼ 自托管 AgentDocker运行在你的服务器上 │ 服务端发起真实 HTTP 请求无 CORS ▼ 目标 API │ 响应返回给 Agent ▼ Agent 将结果返回给浏览器简易实现Node.js约 30 行constexpressrequire(express);const{createProxyMiddleware}require(http-proxy-middleware);constappexpress();app.all(/proxy/*,(req,res){consttargetreq.query.url;if(!target)returnres.status(400).send(Missing url param);createProxyMiddleware({target:target,changeOrigin:true,pathRewrite:()/})(req,res);});app.listen(3000);优点动态代理无需为每个目标域名配一条规则可访问内网服务可以控制访问白名单缺点多维护一个服务有安全风险需防止被滥用为开放代理适用场景API 测试工具、需要动态转发到任意目标的服务。方案六第三方云代理如 Apifox 云端 Agent。第三方提供代理服务开箱即用。优点零部署缺点不能访问内网数据经过第三方服务器安全和隐私问题公网延迟适用场景个人/开发阶段调试公网 API。方案七浏览器扩展如 Chrome 上的 “CORS Unblock”、Apifox 浏览器扩展等。扩展拥有更高权限可以绕过网页的 CORS 限制。优点本地/内网调试方便缺点每个用户需要安装不能用于生产环境适用场景开发调试。方案八关闭浏览器安全策略# Macopen-n-a/Applications/Google\Chrome.app/Contents/MacOS/Google\Chrome--args--user-data-dir/tmp/chrome_dev--disable-web-security# Windowschrome --disable-web-security --user-data-dir%TEMP%/chrome_dev⚠️ 警告仅用于本地开发调试绝不可用于日常使用或生产。关闭安全策略后任何网站都可以访问你的内网资源。方案九Electron / 桌面端应用Electron 的主进程Node.js不受浏览器同源策略限制。Postman、Apifox 桌面版都是基于 Electron。// Electron 主进程直接 HTTP 请求consthttpsrequire(https);https.get(https://api-target.com/data,(res){// 没有 CORS 问题});这也是为什么 Apifox 桌面版默认不需要配置任何代理。四、方案选型决策树你能控制目标服务器吗 ├── 是 → 配置 CORS 响应头方案一 └── 否 → ├── 这是前端 Web 应用 → Nginx 反向代理方案三 ⭐ ├── 这是 API 测试工具 → │ ├── 自建代理服务方案五 │ └── 第三方云代理方案六 └── 这是开发调试 → ├── 浏览器扩展方案七 └── 开发服务器代理方案四五、总结方案是否需要改后端生产可用维护成本CORS 响应头✅ 是✅低Nginx 反向代理❌ 否✅中开发服务器代理❌ 否❌低自托管 Agent❌ 否✅高第三方云代理❌ 否⚠️ 分场景无浏览器扩展❌ 否❌低关闭安全策略❌ 否❌零Electron 桌面端❌ 否✅—核心结论生产环境Nginx 反向代理 CORS 响应头 是目前最主流的两条路。如果能改后端CORS 是标准不能改Nginx 反向代理是事实标准。开发环境Vite/Webpack Dev Server 代理是标配。API 测试工具如 Apifox 网页版使用代理 Agent 方案本质仍是服务端转发。所有方案的核心思想都一样——让请求在服务端完成因为服务端之间没有跨域限制。浏览器端没有真正的直连绕过 CORS方案。