什么是跨域?
你在本地开发一个网页,想从另一个域名的服务器上拉点数据,比如调用天气 API 或用户登录接口。结果浏览器直接报错:‘No 'Access-Control-Allow-Origin' header’——这就是典型的跨域问题。
跨域其实是浏览器出于安全考虑实施的同源策略限制。只要协议、域名、端口有任何一项不同,就算作“非同源”,默认禁止 AJAX 请求获取数据。
常见的跨域场景举例
比如你本地项目运行在 http://localhost:3000,而接口地址是 http://api.example.com:8080。虽然都是本机调试,但域名和端口都不同,浏览器就会拦截这个请求。
再比如上线后,前端部署在 https://www.site.com,后端接口却在 https://api.site.com,看似一家人,也得处理跨域,否则照样拿不到数据。
最常用的解决方案:CORS
CORS(跨域资源共享)是目前最主流的办法,核心是在服务端响应头中添加允许访问的来源。
比如 Node.js + Express 的写法:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
如果你使用 Nginx 做反向代理,也可以在配置里加响应头:
location /api/ {
add_header Access-Control-Allow-Origin http://localhost:3000;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
proxy_pass http://backend;
}
开发阶段临时绕过:代理转发
前端项目常用 Webpack 或 Vite,它们都支持设置代理。比如 Vue 或 React 项目中,在 vue.config.js 或 vite.config.js 中配置:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://api.example.com',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
};
这样你在代码里请求 /api/users,实际会被转发到目标服务器,且不触发跨域,因为请求看起来是发给自己的。
JSONP 还能用吗?
早年没有 CORS 的时候,大家靠 JSONP 来跨域。原理是利用 <script> 标签不受同源策略限制的特点,通过回调函数接收数据。
现在基本只用于老系统维护或某些第三方广告脚本集成。优点是兼容性好,缺点只能发 GET 请求,出错难捕获,安全性也弱一些。
生产环境建议
线上项目别依赖开发服务器的代理功能。该配 CORS 就配,配合精确的 Origin 白名单,避免用通配符 * 暴露敏感接口。
如果前后端同属一个大系统,推荐统一用反向代理把前后端收敛到同一域名下。比如所有请求走 https://example.com,API 路由通过路径区分,从根本上消灭跨域问题。
别忘了预检请求(Preflight)
有些请求会先发一个 OPTIONS 方法的预检请求,检查是否允许真正的请求。特别是带自定义头部或认证信息的时候。
这时候后端必须正确响应 OPTIONS 请求,返回允许的源、方法和头部,否则后续请求不会发出。常见错误就是忘了处理 OPTIONS,导致“看不见的失败”。