跨域请求被浏览器同源策略拦截,服务端实际已接收并响应;CORS预检失败因后端未正确配置Access-Control-Allow-Origin等响应头;开发可配vite/webpack代理临时解决,JSONP已淘汰。
跨域请求不是“不安全所以被禁”,而是浏览器出于同源策略(Same-Origin Policy)主动拦截了 JavaScript 发起的跨域 XMLHttpRequest 或 fetch 请求——服务端其实完全收到了请求,也正常返回了响应,但浏览器拒绝把响应内容交给 JS 脚本。
这是典型的 CORS(Cross-Origin Resource Sharing)预检失败提示。浏览器在发送某些“非简单请求”(如带 Content-Type: application/json、自定义 header、PUT/DELETE 方法)前,会先发一个 OPTIONS 预检请求。如果后端没正确响应这个 OPTIONS,或者没返回必需的 CORS 头,fetch 就会直接报错,连真正的请求都不会发出去。
Access-Control-Allow-Origin(不能是通配符 * + 凭据)credentials: 'include',后端还必须加:Access-Control-Allow-Credentials: true
OPTIONS 返回 200,并带上 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers
代理只在开发服务器生效,不解决生产跨域,但能立刻让接口调通,避免反复改后端配置。
vite.config.ts 中配 server.proxy,例如将 /api 代理到 http://localhost:3000
devServer.proxy 中写对象或数组规则,注意路径重写(rewrite 或 pathRewrite 已废弃,改用 configure 函数)target: 'http://localhost:3000' ✅,'http://localhost:3000/' ❌),否则路径拼接错JSONP 利用 标签不受同源限制的特性,通过动态插入 script 加载远程 JS 执行回调。但它只支持 GET,没有错误捕获机制,无法设 timeout,且服务端必须配合返回函数调用格式(如 callback({...}))。现代浏览器已弃用 document.write,主流框架也不再内置 JSONP 支持。
$.getJSON(url + '?callback=?') 或手动创建 script 标签,说明它没走 CORS,而是降级到了 JSONPdocument.write 在非初始页面加载时直接静默忽略,JSONP 回调可能永远不执行fetch('/api/user', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ id: 123 })
})
.then(r => r.json())
.catch(err => console.error('网络或 CORS 失败:', err))
CORS 的核心从来不在前端“怎么发”,而在于后
端是否明确声明“允许谁、用什么方法、带什么头来访问我”。很多前端开发者卡在“为什么本地能通上线就跨域”,往往是因为 nginx 或云函数网关没透传后端返回的 CORS 响应头,或者反向代理覆盖了它们。