一、前言
众所周知在前端开发过程中和服务端接口进行http请求通讯的过程中,不可避免的会出现跨域的情况。在这么多年的工作当中,遇到过无数多次接口跨域问题,也解决过无数多次跨域问题。概括来说,根据不同场景不同情况,有的是通过前端手段来解决,有的是通过后端手段来解决。
在谈跨域话题之前不得不提的一个前置知识点就是「同源策略」—— same-origin polcy。同源策略的目的是浏览器厂商为了保护用户的信息安全而设立的。这里要注意:只有在浏览器(或webview)的上下文中,并且使用xhr或fetch发起的ajax请求才会有跨域的限制,使用原生native或者如postman等客户端App发起的http请求是不会有跨域的限制。
当然还有跨域读写cookie/Localstorage和跨域操作DOM都是会被同源策略限制的,由于不在本文的讨论范文之内,因此不做过多解释。
二、具体分析
1. 开发阶段跨域
在开发阶段调用服务端接口遇到跨域时,常用的做法可以是使用代理proxy的方式进行处理。
例如
webpack-dev-server中的proxy选项
proxy: {
'/api/v1/': {
target: 'https://another.url.com',
changeOrigin: true,
},
},
原理就是通过中间的代理进行http请求,而不是直接通过浏览器进行,从而绕过跨域的限制。
此外还有jsonp、charles代理等技术在某些场景下也是可以使用的,工作这么多年下来,使用频率不是很高,但是这些知识点还是要知道的。
如果还有遗漏的技能点,请各位老铁在评论区留言。😆
2. 生产环境跨域
跨域资源共享CORS(Cross-Origin Resource Sharing)机制的本质是一系列传输的HTTP头信息,这些HTTP头决定浏览器是否阻止ajax请求的响应。
在服务端配置Response Header的报文头,常见的有配置:
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
一般情况这么配就OK了。
但是又一次遇到一个诡异的问题,同一个接口在chrome浏览器中是正常调用的,但是在Safari浏览器中就提示跨域,提示如图。
在发送options请求预检的过程中配拦截了,提示请求头字段Content-Type不被允许,关键是chrome中是正常的,看起来是在处理这个特殊场景时Safari和chrome的逻辑不一样导致的。
仔细分析对比返回的报文,发现Response Header中还有一个额外的字段:Access-Control-Allow-Headers: *,隐隐感觉就是这个星号有问题。已查资料发现还真是这样。
根据链接中的浏览器兼容性表格显示,*确实在Safari浏览器中不支持。😂 你说是不是坑?
解决办法就是把上面那个改成Access-Control-Allow-Headers: Content-Type把值单独列出来,不要用星号。