跨域问题彻底搞懂:原理、排查和三种解决方案

Cold 发布于 2020-10-18 19 次阅读 643 字 预计阅读时间: 3 分钟 前端开发


跨域大概是前端被问得最多、也最容易懵的问题。每次出问题的报错长得都差不多,原因却五花八门。这篇把原理和排查套路一次讲清,以后再遇到可以直接按流程走。

先搞清:浏览器在拦你,不是服务器拒绝你

同源策略是浏览器的行为。跨域请求其实发出去了、服务器也处理了、响应也回来了,只是浏览器检查响应头里没有"许可",把结果扣下了。所以用 Postman/curl 测接口一切正常、浏览器里就报错,这不是玄学。

排查流程

  • F12 Network 面板,找到那条红色请求,看响应里有没有 Access-Control-Allow-Origin
  • 如果是 GET/POST 之外的方法(PUT/DELETE)或带了自定义 header,先看是不是 预检(OPTIONS)请求失败——真正被拦的往往是预检
  • Console 里那句报错别只看最后半句,前面写了具体原因:Origin 不在许可列表、header 不被允许、还是证书问题

三种解决方案

方案一:后端配 CORS 响应头(正解)

Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400   # 预检结果缓存,减少 OPTIONS 请求

带 cookie 的话,前端要设 credentials: 'include',后端响应 Access-Control-Allow-Credentials: true,且 Origin 不能写 *,必须精确域名。这是最常见的坑。

方案二:Nginx 反向代理(前端域下转发)

location /api/ {
    proxy_pass http://后端内网地址:8080/;
}

浏览器请求的是同源地址,压根不构成跨域。代价是多一层转发,生产上要注意大文件上传的超时配置。

方案三:开发环境 proxy(仅本地)

// vite.config.js
server: {
  proxy: {
    '/api': {
      target: 'http://localhost:8080',
      changeOrigin: true
    }
  }
}

原理同上,webpack/vite 的 dev server 帮你转发。注意它只在开发时有效,上线后没有这层,环境变量里接口地址别写死 localhost。

几个非典型"跨域"报错

  • 报 CORS 错但后端确实配了:检查响应是不是 500/404——错误响应没走 CORS 拦截器的逻辑,header 没带上,浏览器报跨域,其实根因是后端异常
  • JSONP:上古技术,现在基本不用,但面试还爱问。原理是 script 标签不受同源策略限制
  • 跨域不影响 <script>、<img>、<link> 加载资源,这就是为什么 CDN 的 JS/CSS 能随便引
和喜欢的一切在一起~
最后更新于 2020-10-18