前言

自建了一个 live2d 后端 api 接口,使用时发生了各种跨域问题,于是记录一下。

https://github.com/fghrsh/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 制定的标准,允许服务器声明哪些来源的请求是被允许的。

浏览器行为:

  1. 发送请求前,浏览器会自动添加请求头 Origin,说明请求来源。

  2. 如果是复杂请求(如 PUT、PATCH、自定义头等),会先发送一个 预检请求(OPTIONS)

  3. 服务器响应中包含 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
    }));

问题描述:设置了 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 同源,从而避免跨域。

四、跨域请求的安全注意事项

  1. 不建议设置 Access-Control-Allow-Origin: *Allow-Credentials: true 同时存在,这会被浏览器拦截。

  2. 验证 Origin 的合法性,尤其是敏感数据接口。

  3. 严格控制允许的方法和头部,避免开放过多权限。

五、总结

方式

是否推荐

场景说明

设置 CORS 响应头

✅ 推荐

后端可控

Nginx 反向代理

✅ 推荐

静态资源部署层处理跨域

JSONP

❌ 过时

仅限 GET,存在安全隐患

iframe + postMessage

⚠️ 特殊场景

高级交互需要