「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」。
跨域是前后端联调老生常谈的问题了,今天来简要概括一下关于前端跨域方法以及本地如何代理。
什么是跨域
首先是因为浏览器有同源策略 Same origin policy ,简单来说就是不允许不同host、端口或者协议不同的网页获取另外一个域名下的资源。不同源的定义是, host、 端口、协议(http vs https)不同就算不同源,前端俗称的跨域简单来说一个域去另外一个域下获取资源。
前端跨域的方法
-
使用本地代理服务器(手脚架插件,Node插件等),不走浏览器就没有同源策略机制也就不会触发跨域检测; 这也就为什么用postman时不会触发跨域报错;
-
Nginx反向代理,类似本地代理服务器,不过是在目标服务器上做的转发;
-
postMessage:相同浏览器页面之间跨域,通过postMessage指定域名跟目标域监听message消息发跟接收消息;
-
iframe+location.hash: 相同浏览器页面之间跨域,a想要跨域与b通信,通过同源中间页c,a加载b的iframe 利用hash传值,b再同理把回应再传向c,c可以访问a页面所以对象从而将回应传递给a;
-
iframe+window.name: 创建一个代理域的iframe,利用iframe的src属性加载外域,然后将外域的window.name保存在代理域,本地域获取到代理域的window.name之后销毁代理域,保证数据不被其他域获取的同时实现window.name从外域传递到本地域;
-
iframe+document.domain,主要是相同主域名,主子窗口页面强行修改document.domain实现与主窗口同源;
-
Jsonp:通过script标签发起get请求,服务器接收请求解析前端传去过去的回调,并把数据传入该回调;
-
其他协议例如Websocket。
其中3,4,5,6都属于使用Bom API来实现跨域,所以只能实现页面之间的跨域,适合同一站点的外链页面与主页面直接的通信等。从前后端接口请求的方面来看,让后端去设置服务器CORS接口,触发CORS流程才是王道(减少前端工作量),了解更多可以查看 跨域资源共享
不成熟观点:从接口请求层面看纯前端跨域根本就是伪命题,没有服务器设置CORS根本很难绕过同源机制(越容易就越不安全)。
本地代理流程
当我在a.com 想调部署在b.com(服务器未CORS处理)下的接口时,浏览器会阻止我并向我丢过一个COR error:Access to XMLHttpRequest at 'target.com' from origin 'http://localhost:8001' has been blocked by CORS policy.
以Vue cli为例子,在vue.config.js 里的devServer加上
proxy: { '/api': { target: 'b.com', changeOrigin: true, pathRewrite: { '/api': '', }, }
然后再在请求里加上比如 要请求 b.com/list axios.get('api/list') 就可以成功请求。
原理:当发起请求时,浏览器会把请求发到代理服务器,然后代理服务器会把就会把请求改成 b.com/list发给b.com的服务器, 跨域的本质是ajax引擎的拦截 ,不走ajax引擎也就不会拦截。
小插曲
今天联调时,我想修改请求头里的origin时,发现怎么改origin 都还是localhost
proxy: { '/api': { target: 'b.com', changeOrigin: true, pathRewrite: { '/api': '', }, onProxyReq: function (request) { request.setHeader('origin', 'b.com') }, }, }
我以为onProxyReq的事件没触发, 就带着疑惑去搜,看了答案之后知道 在vue-cli 3.0配置proxy的onProxyReq事件没有触发 。本地代理服务器的过程,是localhost浏览器发请求到代理服务器,代理服务器修改请求头origin,再去发给b.com, 然后真实服务器再返回请求给浏览器。中间商赚没赚到差价控制台是看不见的。
总结
本地代理服务器是开发阶段比较常用的手段,线上环境还是需要服务器去设置CORS。