Web2.0以来,Ajax的出世,解决了传统表单提交页面跳转,闪烁白屏等问题。使得Web页面能够实现局部更新,不只减小了网络带宽,还大大提高了用户体验。html
但Ajax并不是是一把万能的钥匙,足以打开Web通讯这扇大门,当请求遇到跨域通讯时,Ajax就没辙了。前端
Web的快速发展让开发走向工程化的同时,要求工做维度进行划分(前端后端分工明细),以便扩展维护日益复杂庞大的项目需求。而先后端分离的开发方式正是这种需求背景下衍生的产物。(之前混编的代码如今是不再想看到)html5
先后端分离的开发方式,如何进行数据通讯是开发人员绕不过去的问题。做为开发同窗的小伙伴客户端的浏览器,有点小调皮还作了一个同源策略的限制,当咱们的数据请求遇到不一样源的状况下(跨域),咱们就得尝试其它的通讯方法,不能Ajax一条道走到黑。web
同源策略限制从一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。
同源要求协议,域名,端口(默认80)三者都相同,不然为非同源。json
var xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft') var data = opt.data, url = opt.url, type = opt.type.toUpperCase(), dataArr = []; for (var k in data) { dataArr.push(k + '=' + data[k]); } if (type === 'GET') { url = url + '?' + dataArr.join('&'); xhr.open(type, url.replace(/\?$/g, '', true); xhr.send(); } if (type === 'POST') { xhr.open(type, url, true); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.send(data.join('&')); } xhr.onload = function() { if (xhr.status === 200 || xhr.status === 304) { var res; if (opt.success && opt.success instanceof Function) { res = xhr.responseText; if (typeof res === 'string') { res = JSON.parse(res); opt.success.call(xhr, res) } } else { if (opt.error && opt.error instanceof Function) { opt.error.call(xhr, res); } } } }
同源下,咱们能够直接使用Ajax来与后端同窗作数据通讯,可是遇到跨域请求时,咱们就得更换手中这把Ajax的钥匙,来从新配钥匙开锁后端
JSONP原理:客户端经过动态建立script标签异步加载来实现,服务端callback返回客户端定义的方法名,让客户端进行调用获取数据。跨域
只支持Get请求 (GET与POST的区别这里暂不细讲)浏览器
// 客户端发送请求 <script src="http://www.abc.com?data=name&callback=jsonpname"></script> <script> jsonpname({ data: { ... } }) </script>
Hash原理:经过window.onhashchange
事件监听来获取url中hash值来实现数据传输。与Get同样,有Url长度限制安全
// A中代码 var B = document.getElementdByTagName('iframe'); B.src = B.src + '#' + 'data'; // B中代码 window.onhashchange = function(){ var data = window.location.hash; }
postMessage是HTML5的API,可参考开发文档window.postMessage服务器
// A.com向B.com发送信息 Bwindow.postMessage('data','http://B.com') // B中监听 window.addEventListener('message', function(event){ console.log(event.origin); // http://A.com console.log(event.source); // Bwindow console.log(event.data); // data }, false)
项目中应用场景:
WebSocket是HTML5开始提供的一种在单个 TCP 链接上进行全双工通信的协议,自己不受同源限制。
// WebSocket代码示例 var ws = new WebSocket('wss://echo.websocket.org'); ws.onopen = function (evt) { console.log('Connection open ...'); ws.send('Hello WebSocket!'); }; ws.onmessage = function (evt) { console.log('Received Message: ' + evt.data); ws.close(); } ws.onclose = function (evt) { console.log('Connection closed.'); }
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它容许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
浏览器兼容在XHR(IE8/9)及XHR2(>=IE10)下须要作兼容处理。
// CORS代码示例 fetch('/url', { method: 'get', }).then(function(res){ ... }).catch(function(err) { // 错误 })
JSONP有更好的兼容性,能兼容低版本浏览器,可是基于Get传输数据,会由于浏览器Url长度限制而限制数据大小。CORS在不考虑低版本浏览器时,无疑是目前最好先后端通讯方案(单向),双向选择WebSocket,而多个页面之间的数据通讯,如内嵌iFrame等,则推荐postMessage。
每种方案有不一样的应用场景,解决问题不仅有一种解决方案,实际项目开发中,需根据实际需求来挑选最优的方案。
参考资料
做者:以乐之名 本文原创,有不当的地方欢迎指出。转载请指明出处。