JavaScript跨域是浏览器基于同源策略主动拦截请求,协议、域名、端口任一不同即触发;核心错误“No 'Access-Control-Allow-Origin' header”源于浏览器收到响应后校验失败,需后端正确处理预检OPTIONS并返回合法CORS头。
JavaScript 跨域不是“代码写错了”,而是浏览器主动拦截了本该发出的请求。核心判断依据是:协议、域名、端口三者中任意一个不同,就算跨域。https://a.com 请求 https://b.com/api 会被拦;http://localhost:3000 请求 http://localhost:8080 同样被拦——端口不同也算跨域。
这个错误不是后端没收到请求,而是浏览器在收到响应后,发现响应头里没有 Access-Control-Allow-Origin,就拒绝把响应结果交给 JS。关键点在于:浏览器先发预检请求(OPTIONS),后端必须正确响应它,才能放行后续的 GET 或 POST。
常见疏漏:
OPTIONS 预检Credentials(比如 withCredentials: true),但后端返回的 Access-Control-Allow-Origin: * 不合法——必须指定
具体域名Access-Control-Allow-Headers,但漏了前端实际发送的自定义头(如 X-Auth-Token)不改后端、不碰浏览器策略,靠本地开发服务器转发请求,让浏览器认为“还是同源”。重点不是“配代理”,而是配对路径和重写规则。
Vite 示例(vite.config.ts):
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
注意:changeOrigin: true 必须开,否则后端收到的 Host 头还是前端地址;rewrite 是为了去掉 /api 前缀,否则后端收不到真实路径。
前端改不了跨域限制,最终必须由后端响应正确的 CORS 头。典型配置项:
Access-Control-Allow-Origin:可填具体域名(如 https://myapp.com),不能填 * + credentials
Access-Control-Allow-Credentials:设为 true 时,前端才能传 cookie 或 authorizationAccess-Control-Allow-Methods:列出允许方法,如 GET, POST, PUT, DELETE
Access-Control-Allow-Headers:列出前端可能带的头,如 Content-Type, Authorization
如果后端用 Express,常用中间件是 cors,但别直接 app.use(cors()) —— 默认允许所有源,不安全。应显式配置:
app.use(cors({
origin: 'https://myapp.com',
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization']
}));
跨域真正麻烦的地方不在“怎么配”,而在于前后端对同一场景的理解错位:前端以为发出去了,其实被浏览器吞了;后端以为没收到请求,其实预检就被拒了。查问题先看 Network 面板里有没有 OPTIONS 请求,再看它的响应头。