CORS跨域有哪些坑?一文带你彻底搞懂同源策略

哎哟喂,说到CORS跨域这事儿,我这心里就一肚子苦水啊!前阵子调试接口的时候,被这个“跨域”折磨得差点把键盘给砸了,相信不少前端小伙伴都经历过这种崩溃瞬间——明明代码写得没毛病,浏览器就是给你甩脸色,报个“Access-Control-Allow-Origin”错误,让你一脸懵圈,今天咱们就好好唠唠,CORS跨域到底有哪些门道,保准你看完能少踩几个坑!
首先得明白,浏览器这货规矩特别多,它搞了个叫“同源策略”的东西,简单说就是协议、域名、端口这三样必须一模一样,才能互相访问资源,你说这严不严格?就像你家门锁必须配你家钥匙,隔壁邻居的钥匙想开你家门?门儿都没有!这就导致了一个很现实的问题:前端开发时,本地跑着localhost:8080,后端接口在api.example.com,这俩端口协议都不一样,妥妥的跨域了,这时候CORS跨域就得出马了。
那CORS跨域到底有哪些解决方案呢?让我掰着手指头给你数数哈。
第一种,最正统的——后端配置CORS响应头。 这招就像给门卫大爷打个招呼:“这几个域名的兄弟来,放行!”后端在返回响应时,加上Access-Control-Allow-Origin这个响应头,指定允许的域名或者直接用通配符,哎,但是啊,这招虽然省事儿,可不支持携带Cookie,你要是做登录认证啥的,用准得翻车,还得设置Access-Control-Allow-Credentials: true配合指定域名,才能带凭证,另外还有Access-Control-Allow-Methods限流能用的HTTP方法,比如POST、GET、PUT这些;Access-Control-Allow-Headers限定请求头,这配置要是搞错了,浏览器照样给你脸色。
第二种,Nginx反向代理。 这绝对是前端狗子的救命稻草啊!原理也简单,就是让Nginx当前中间人,把不同域的请求转发到目标服务器,比如你前端在a.com,Nginx配置一个路由,把/api开头的请求代理到http://backend-server,这样浏览器看到的都是同源的,也就没有跨域问题了,我最喜欢这招了,因为前端代码不用动一行,后端也不用改,完美!
第三种,JSONP(虽然有点老古董,但偶尔还能用)。 这招巧妙啊,利用<script>标签不受同源策略限制的特性,动态创建一个script标签,src指向带回调函数的接口地址,服务器返回类似callback({data:...})这样的JS代码,然后前端全局函数就能收到数据了,可问题是,JSONP只支持GET请求,而且有安全隐患,现代项目基本都抛弃它了。
第四种,WebSocket协议。 嘿,这招不按常理出牌啊!WebSocket压根就不受同源策略限制,建立连接后双向通信爽歪歪,适合实时性要求高的场景,比如在线聊天、协作编辑,但是呢,得后端支持升级协议,而且网络环境如果太复杂,比如有防火墙,WebSocket可能连不上。
第五种,postMessage跨窗口通信。 这招适用于iframe嵌入的场景,父页面和iframe里的子页面虽然不同源,但可以通过window.postMessage互相发消息,前提是对方得监听message事件,然后校验event.origin是不是安全的来源,我就记得有一次嵌了个第三方图表组件,跨域通信全靠这招,真是又爱又恨。
行了,列了这么多方法,你肯定想知道到底该选哪个吧?我个人经验是这样的:如果是自己全栈可控,后端配置CORS是最规范的;如果后端动不了,Nginx代理永远是最顺手的选择;至于其他方法,能不用尽量别用,还有啊,坑爹的是,预检请求(OPTIONS)也是个重灾区,就是当你的请求不是简单请求(比如带了Content-Type: application/json或自定义头),浏览器会先发个OPTIONS探测一下,如果后端没处理好这个预检,真实请求根本发不出去,我那时调试了半天,后来发现是后端漏了处理OPTIONS,气得我直拍大腿!
最后啊,真心建议各位:开发环境直接用Vite或Webpack的proxy代理,省心又高效;生产环境再按需配置Nginx,别一上来就想着硬刚CORS,能靠代理解决的都不算事儿。
好了,啰嗦了这么多,希望能帮大家把CORS跨域这事儿理清楚,下次再遇到跨域报错,别慌,先对着这几条排查一遍,准能解决,要是还搞不定,欢迎在评论区留言,咱们一起吐槽讨论,毕竟踩坑路上不孤单嘛!加油,打工人!