智用指南
第二套高阶模板 · 更大气的阅读体验

JavaScript跨域问题详解与实战解决方案

发布时间:2025-12-12 22:48:52 阅读:287 次

什么是ref="/tag/137/" style="color:#C468A7;font-weight:bold;">JavaScript跨域问题

在开发网页应用时,你可能会遇到浏览器报出这样的错误:"No 'Access-Control-Allow-Origin' header is present"。这其实就是JavaScript的跨域问题。简单来说,当你在一个域名下请求另一个域名的数据时,比如从 https://site-a.comhttps://api.site-b.com 发起 AJAX 请求,浏览器出于安全考虑会阻止这个请求,除非对方服务器明确允许。

这种机制叫“同源策略”,是浏览器保护用户数据不被随意窃取的重要手段。所谓“同源”,指的是协议、域名、端口三者完全相同。哪怕只是端口不同,比如 http://localhost:3000http://localhost:4000,也算跨域。

常见的跨域场景

你在本地调试前端项目时,后端接口通常跑在另一个端口上。比如你用 Vue 或 React 开发,前端是 http://localhost:5173,而接口地址是 http://localhost:3000/api/users,这时候一发请求就跨域了。再比如,你的网站想调用第三方地图 API 或天气服务,如果对方没配置 CORS,也会失败。

CORS:跨域资源共享

最标准的解决方式是通过 CORS(Cross-Origin Resource Sharing)。它需要后端配合,在响应头中加入允许跨域的字段。例如:

Access-Control-Allow-Origin: https://your-site.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization

如果你能控制后端代码,Node.js 的 Express 框架可以这样设置:

app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://your-site.com');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});

开发阶段也可以直接允许所有来源(仅限测试):

res.header('Access-Control-Allow-Origin', '*');

JSONP:老但有效的办法

在 CORS 出现之前,大家常用 JSONP 来绕过跨域限制。它的原理是利用 <script> 标签不受同源策略影响的特性,动态插入一个脚本,回调函数名由前端指定。

比如你想获取用户数据:

function handleUserData(data) {
console.log('用户信息:', data);
}

const script = document.createElement('script');
script.src = 'https://api.example.com/user?callback=handleUserData';
document.head.appendChild(script);

后端返回的内容必须是函数调用的形式:

handleUserData({"name": "张三", "age": 28});

不过 JSONP 只支持 GET 请求,安全性也较差,现在多用于兼容老旧系统。

代理服务器:开发环境利器

如果你没法改后端,又不想上线前一直被跨域困扰,可以在开发时用代理。比如在 Vite 项目中配置 vite.config.js

export default {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
}
}
}
}

这样一来,你原本要请求 /api/users,实际会被转发到 http://localhost:3000/api/users,因为请求是从本地服务器发出的,不走浏览器直接跨域,自然就没问题。

Nginx 反向代理部署方案

上线后也可以用 Nginx 做反向代理。比如把所有 /api/ 开头的请求转给真正的后端服务:

location /api/ {
proxy_pass http://backend-server:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

这样前端和 API 看起来是同一个域名,彻底避开跨域问题。

避免踩坑的小建议

发送携带 Cookie 的请求时,前端要设置 credentials: 'include',同时后端的 Access-Control-Allow-Origin 不能为 *,必须是具体域名,否则浏览器会拒绝。

fetch 示例:

fetch('https://api.example.com/login', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username: 'test', pwd: '123' })
})

对应的后端响应头应包含:

Access-Control-Allow-Origin: https://your-site.com
Access-Control-Allow-Credentials: true