Why : 爲何會產生跨域問題javascript
由瀏覽器的同源策略(協議+域名+端口)致使。同源策略是基於瀏覽器安全角度產生的。html
How : 如何解決跨域問題前端
1.經過jsonp方式,原理是使用<script>的src自己支持跨域vue
優勢:低版本瀏覽器也可使用 缺點:只支持get方法,且只能夠用於傳遞數據沒法進行DOM查詢,安全性低,必須後端配合。
一:原生實現html5
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP實現跨域</title> </head> <body> <div id="mydiv"> <button id="btn">點擊</button> </div> </body> <script> function handleResponse(res){ console.log(JSON.stringify(res)); } </script> <script type="text/javascript"> window.onload = function() { var oBtn = document.getElementById('btn'); oBtn.onclick = function() { 0 var script = document.createElement("script"); // 傳參並指定回調執行函數爲callBack script.src = "http://xxxx.com?callback=handleResponse"; document.body.insertBefore(script, document.body.firstChild); }; }; </script> </html>
二:jq ajax實現java
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jQuery實現JSONP</title> </head> <body> <div id="mydiv"> <button id="btn">點擊</button> </div> </body> <script type="text/javascript" src="https://code.jquery.com/jquery-3.1.0.min.js"></script> <script type="text/javascript"> $(function() { $("#btn").click(function() { $.ajax({ async: true, url: "http://xxxx.com", type: "GET", dataType: "jsonp", // 請求方式爲jsonp jsonp: 'callback', //指定一個查詢參數名稱來覆蓋默認的 jsonp 回調參數名 callback jsonpCallback: 'handleResponse',//自定義回調函數名 data: { count: 1 }, success: function(response, status, xhr) { console.log('狀態爲:' + status + ',狀態是:' + xhr.statusText); console.log(response); } }); }); }); </script> </html>>
三:vue.js: vue實現jquery
this.$http.jsonp('http://xxx.com', { params: {}, jsonp: 'callBack' }).then((res) => { console.log(res); })
2.使用CORS(跨域資源共享)設置請求頭ios
普通跨域請求:只服務端設置Access-Control-Allow-Origin便可,前端無須設置,若要帶cookie請求:先後端都須要設置。ajax
需注意的是:因爲同源策略的限制,所讀取的cookie爲跨域請求接口所在域的cookie,而非當前頁。json
一、 前端設置
1)原生ajax
// 前端設置是否帶cookie xhr.withCredentials = true; 示例代碼: var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容 // 前端設置是否帶cookie xhr.withCredentials = true; xhr.open('post', 'http://www.domain2.com:8080/login', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('canshu=xxx'); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } };
2)jQuery ajax
$.ajax({ ... xhrFields: { withCredentials: true // 前端設置是否帶cookie }, crossDomain: true, // 會讓請求頭中包含跨域的額外信息,但不會含cookie ... });
3)vue框架
1/axios設置: axios.defaults.withCredentials = true 2/vue-resource設置: Vue.http.options.credentials = true
3.使用 iframe 配合 window 自帶的 name 屬性
優勢:操做簡單,不要求後端配合 缺點:name的大小有限制,通常是2M左右
window.name屬性的獨特之處:name值在不一樣的頁面(甚至不一樣域名)加載後依舊存在,而且能夠支持很是長的 name 值(2MB)。
(1)a.html:(http://www.domain1.com/a.html) var proxy = function(url, callback) { var state = 0; var iframe = document.createElement('iframe'); // 加載跨域頁面 iframe.src = url; // onload事件會觸發2次,第1次加載跨域頁,並留存數據於window.name iframe.onload = function() { if (state === 1) { // 第2次onload(同域proxy頁)成功後,讀取同域window.name中數據 callback(iframe.contentWindow.name); destoryFrame(); } else if (state === 0) { // 第1次onload(跨域頁)成功後,切換到同域代理頁面 iframe.contentWindow.location = 'http://www.domain1.com/proxy.html'; state = 1; } }; document.body.appendChild(iframe); // 獲取數據之後銷燬這個iframe,釋放內存;這也保證了安全(不被其餘域frame js訪問) function destoryFrame() { iframe.contentWindow.document.write(''); iframe.contentWindow.close(); document.body.removeChild(iframe); } }; // 請求跨域b頁面數據 proxy('http://www.domain2.com/b.html', function(data){ alert(data); }); (2)proxy.html:(http://www.domain1.com/proxy.... 中間代理頁,與a.html同域,內容爲空便可。 (3)b.html:(http://www.domain2.com/b.html) <script> window.name = 'This is domain2 data!'; </script>
4.使用h5新增的postMessage方法
優勢:操做簡單,不要求後端配合 缺點:早期瀏覽器不支持
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是爲數很少能夠跨域操做的window屬性之一,它可用於解決如下方面的問題:
a.) 頁面和其打開的新窗口的數據傳遞
b.) 多窗口之間消息傳遞
c.) 頁面與嵌套的iframe消息傳遞
d.) 上面三個場景的跨域數據傳遞
用法:postMessage(data,origin)方法接受兩個參數
data: html5規範支持任意基本類型或可複製的對象,但部分瀏覽器只支持字符串,因此傳參時最好用JSON.stringify()序列化。
origin: 協議+主機+端口號,也能夠設置爲"*",表示能夠傳遞給任意窗口,若是要指定和當前窗口同源的話設置爲"/"。
(1)a.html:(http://www.domain1.com/a.html) <iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe> <script> var iframe = document.getElementById('iframe'); iframe.onload = function() { var data = { name: 'xxx' }; // 向domain2傳送跨域數據 iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com'); }; // 接受domain2返回數據 window.addEventListener('message', function(e) { alert('data from domain2 ---> ' + e.data); }, false); </script> (2)b.html:(http://www.domain2.com/b.html) <script> // 接收domain1的數據 window.addEventListener('message', function(e) { alert('data from domain1 ---> ' + e.data); var data = JSON.parse(e.data); if (data) { data.number = 16; // 處理後再發回domain1 window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com'); } }, false); </script>