前言
自建了一个 live2d 后端 api 接口,使用时发生了各种跨域问题,于是记录一下。
一、什么是跨域?
“跨域”是指浏览器出于安全考虑,阻止一个网站的脚本对另一个源(域名、协议、端口)下的资源进行访问。这个安全策略称为同源策略(Same-Origin Policy),它限制了不同源之间的交互,以防止恶意行为如 XSS、CSRF 攻击等。
举个例子:
http://example.com 请求 http://api.example.com 是跨域
http://example.com:80 请求 http://example.com:8080 是跨域
http://example.com 请求 https://example.com 也是跨域
只有“协议 + 域名 + 端口”完全一致,才是同源。
二、CORS:现代浏览器的跨域解决方案
跨域资源共享(CORS,Cross-Origin Resource Sharing)是 W3C 制定的标准,允许服务器声明哪些来源的请求是被允许的。
浏览器行为:
发送请求前,浏览器会自动添加请求头
Origin
,说明请求来源。如果是复杂请求(如 PUT、PATCH、自定义头等),会先发送一个 预检请求(OPTIONS)。
服务器响应中包含 CORS 相关头部时,浏览器才会允许响应被前端访问。
常见响应头说明:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
三、常见跨域场景与解决方法
场景1:开发环境本地请求后端接口报 CORS 错误
问题描述:前端在 localhost:3000
,后端在 localhost:8000
,请求时报 CORS policy
错误。
解决方案:
修改后端响应头,允许
localhost:3000
:Access-Control-Allow-Origin: http://localhost:3000
如果使用 Node.js (Express):
const cors = require('cors'); app.use(cors({ origin: 'http://localhost:3000', credentials: true }));
场景2:前端携带 Cookie 请求失败
问题描述:设置了 withCredentials: true
,但浏览器依然拦截响应。
解决方案:
前端配置 axios:
axios.get('/api/data', { withCredentials: true });
后端响应必须包含:
Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: https://your-domain.com // 注意不能是 *
场景3:Nginx 代理解决跨域
如果无法修改后端代码,也可以通过反向代理解决跨域:
location /api/ {
proxy_pass http://backend-server/;
proxy_set_header Host $host;
}
前端请求 /api/
,由 Nginx 转发至后端,前端与 Nginx 同源,从而避免跨域。
四、跨域请求的安全注意事项
不建议设置
Access-Control-Allow-Origin: *
与Allow-Credentials: true
同时存在,这会被浏览器拦截。验证 Origin 的合法性,尤其是敏感数据接口。
严格控制允许的方法和头部,避免开放过多权限。