用戶瀏覽網站時不免須要將一些常常用到的信息,緩存在本地以提高交互體驗,避免一些多餘的操做。那麼這些信息中不免有些就會涉及用戶的隱私,怎麼保證用戶的信息不在多個站點之間共享,以達到可用的最小範圍,這邊引出了瀏覽器的同源策略。那麼...javascript
什麼是同源策略?
同時知足如下三個條件的網頁稱爲同源:html
非同源的網頁將受到如下限制:前端
同源策略是必要的,但這些限制有時也會對一些合理的使用帶來不便,這便引出了跨域通訊的需求。java
常見的跨域通訊方式有以下集中:jquery
JSONP的原理是,首先客戶端動態添加一個<script>
元素,向服務器請求JSON數據,在請求的URL中添加search字段,指定回調函數名;服務器在收到請求後,會將數據放在指定名字的回調中傳回來。實現源碼:ios
/** * jsonp * @param {[type]} url [description] * @param {[type]} onsucess [description] * @param {[type]} onerror [description] * @param {[type]} charset [description] * @return {[type]} [description] */ const jsonp = function(url, onsucess, onerror, chartset){ let callbackName = getName('tmp_jsonp') window[callbackName] = function(){ if(onsucess && onsucess instanceof Function){ onsucess(arguments[0]) } } let script = createScript(url + '&callback=' + callbackName, charset) script.onload = script.onreadystatechange = function () { // script標籤加載完成(即jsonp請求完成)後移除建立的臨時標籤 if(!script.readyState || /loaded|complete/.test(script.readyState)){ script.onload = script.onreadystatechange = null // 移除該script的 DOM 對象 if (script.parentNode) { script.parentNode.removeChild(script) } window[callbackName] = null } } script.onerror = function () { if (onerror && util.isFunction(onerror)) { onerror(); } } document.getElementsByTagName('head')[0].appendChild(script) } /** * 獲取一個隨機的5位字符串 * @param {string} prefix [字符前綴] * @return {string} [字符集] */ const getName = function (prefix) { return prefix + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5) } /** * 在頁面中建立script * @param {string} url [url] * @param {string} charset [字符集] * @return {string} [建立完成的script標籤] */ const createScript = function (url, charset) { let script = document.createElement('script') script.setAttribute('type', 'text/javascript') charset && script.setAttribute('charset', charset) script.setAttribute('src', url) script.async = true return script }
hash方式主要用在內嵌iframe的父子窗口間的通訊,原理是URL的#
後部分的改變不會使頁面刷新。
(1)父窗口向子窗口發送數據web
// 父窗口向子窗口發送數據 let src = orignURL + '#' + data document.getElementById('myIframe').src = src // 子窗口接收父窗口發送的數據 window.onhashchange = function(){ let message = window.location.hash ... }
(2)子窗口向父窗口發送數據,也同理ajax
parent.location.herf = target + '#' + hash
首先建立目標窗口的window對象,而後經過該對象的postmessage方法傳遞數據,最後目標窗口經過監聽message事件來接受數據。json
// 發送數據 let bWindow = window.open('http://b.com', 'title') bWindow.postmessage('hello message', 'http://b.com') // 接受數據 window.addEventListener('message', function(e){ // e.source 發送消息窗口的引用 // e.origin 發送消息的網址 // e.data 發送消息的內容 })
使用postmessage時須要注意的問題:axios
message
事件的響應,接收時須要對發送方進行驗證*
進行羣發// ws和wss的區別就是加不加密 let ws = new WebSocket('ws://xx.com') ws.onopen = function(e){} ws.onmessage = function(e){} ws.onclose = function(e){}
能夠簡單理解爲跨域通訊的ajax,須要瀏覽器和服務器同時支持,主要關鍵仍是須在瀏覽器端進行配置。可參考CORS配置說明
除了跨域通訊,前端最常接觸的即是先後端通訊,常見的先後端通訊方式有如下三種:
Vue是個沒什麼入侵性的框架,因此在ajax方面能夠有不少選擇:
/** * 原生JS實現ajax * @param {object} options [傳入參數] * @return {[type]} [description] */ const ajax = function(options){ var opt = { url: '', type: 'get', data: {}, success: function () {}, error: function () {}, } Object.assign(opt, options) if(opt.url){ let xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP') let data = opt.data, url = opt.url, type = opt.type.toUpperCase(), dataArr = [] for(let 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(dataArr.join('&')) } xhr.onload = () => { if(xhr.status === 200 || xhr.status === 304 || xhr.status === 206){ let 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) } } } } }