浏览器跨域问题怎么解决

时间:2026-10-17 05:11:29来源:力不从心网 作者:探索

前端调接口,浏览浏览器控制台甩给你一行红字:Access to fetch at 'https://api.other.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy。器跨你盯着屏幕,域问代码逻辑没问题,题解Postman 里请求也跑得通,浏览偏偏浏览器就不给过。器跨这不是域问 bug,是题解浏览器在保护你——准确地说,是浏览保护它背后的用户。

跨域的器跨本质就一句话:浏览器出于安全考虑,默认禁止页面向不同源(协议、域问域名、题解端口任一不同)的浏览服务器发起某些请求并读取响应。注意,器跨请求可能已经发出去了,域问服务器也处理了,但浏览器把响应拦在了 JS 手里。这点很多人搞混,以为请求没发出去。不是的,是“发了,但不给你看”。

后端加几个响应头,最省事

如果后端是你自己能改的,直接加 CORS 响应头。Node/Express 里用 cors 中间件,一行 app.use(cors()) 就完事。Nginx 里加 add_header Access-Control-Allow-Origin。Spring Boot 用 @CrossOrigin 注解或者全局配置。

但有个坑我踩过:Access-Control-Allow-Origin 设成 * 的时候,如果请求带 cookie(credentials: 'include'),浏览器直接拒绝。通配符和凭证不能共存,必须指定具体域名。这个规则卡了不少人,包括当年的我。

还有预检请求。当你发的是 PUT、DELETE,或者带了自定义 header,浏览器会先发一个 OPTIONS 请求探路。后端如果没处理 OPTIONS,预检就挂了,真正的请求根本发不出去。很多人只配了 GET 的 CORS 头,然后纳闷为什么 POST 不行——大概率就是预检没过。

开发阶段,代理是王道

后端不归你管?或者生产环境压根不允许改?开发阶段最舒服的方案是 dev server 代理。Webpack Dev Server 或 Vite 都支持 proxy 配置:

// vite.config.js server: {  proxy: {  '/api': {  target: 'https://api.other.com', changeOrigin: true, rewrite: path => path.replace(/^\/api/, '') } } }

前端请求写 /api/data,dev server 帮你转发到目标服务器。浏览器看来,请求是发给同源的 dev server,压根不涉及跨域。这招在本地开发时几乎万能,配置一次管到底。

但注意,代理只在开发服务器生效。打包上线之后,/api 指向的是你部署的静态服务器,不是 dev server。生产环境要么用 Nginx 做反向代理,要么后端老老实实配 CORS。

JSONP 和 postMessage,特定场景的偏方

JSONP 算是历史遗留方案了。原理是 <script> 标签不受同源策略限制,通过动态插入 script 标签,让后端返回一段调用函数的 JS 代码。只支持 GET,安全性也一般。2024 年了,除非维护老项目,不建议主动选它。

postMessage 解决的是另一个问题:两个不同源的页面之间怎么通信。比如你嵌了一个 iframe,父页面和 iframe 之间要传数据,用 window.postMessage 加 message 事件监听。这不算严格意义上的“解决跨域请求”,但属于跨域通信的范畴,用对了很顺手。

Nginx 反代,生产环境的常规操作

生产环境最常见的是 Nginx 反向代理。前端页面和 API 挂在同一个域名下,用路径区分:/ 走静态资源,/api 转发到后端服务。浏览器看来全是同源请求,CORS 问题根本不存在。

这种方案的好处是不依赖后端改代码,运维层面就能搞定。坏处是配置写错了排查起来烦,proxy_pass 后面加不加斜杠、proxy_set_header 有没有传对,每个细节都可能让你多加班两小时。

跨域不是敌人,是浏览器安全模型的一部分。理解它为什么存在,比死记几种解决方案有用得多。遇到报错先看控制台具体信息,是缺 Allow-Origin 还是预检失败,对症下药,比网上搜一堆代码挨个试快得多。

相关内容
推荐内容