參考:https://www.phpmianshi.com/?id=88
1.爲啥出現跨域
在制定Html規則時,爲了安全的考慮,一個源的腳本(網頁,網站)不能與另一個源的資源進行交互,
所以就引發一個詞叫做“同源策略”。
所謂同源(即指在同一個域),就是兩個頁面具有相同的協議(protocol),主機(host)和端口號(port)
2.啥是跨域
當協議,主機,和端口號有一個不同時,就是跨域。
3.解決跨域的方法
對最主要的AJAX跨域來說(也就是平常調接口時):
1)(後端)服務器配置CORS(跨域資源共享)
CORS(Cross-Origin Resource Sharing)跨域資源共享,定義了必須在訪問跨域資源時,瀏覽器與服務器應該如何溝通。CORS背後的基本思想就>是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功還是失敗。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低>於IE10。整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。對於開發者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏>覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。
CORS案例:
瀏覽器在發出CORS請求時會在頭信息之中增加一個Origin字段;
後端返回代碼中增加三個字段
header(“Access-Control-Allow-Origin”:“”); // 必選 允許所有來源訪問
header(“Access-Control-Allow-Credentials”:“true”); //可選 是否允許發送cookie
header(“Access-Control-Allow-Method”:“POST,GET”); //可選 允許訪問的方式
普通跨域請求:只服務端設置Access-Control-Allow-Origin即可,前端無須設置,若要帶cookie請求:前後端都需要設置。
目前,所有瀏覽器都支持該功能(IE8+:IE8/9需要使用XDomainRequest對象來支持CORS)),CORS也已經成爲主流的跨域解決方案。
但不能實現修改cookie中domain信息,不方便當前域cookie寫入,即不能實現登錄認證。
2)(後端)nginx,反向代理,把跨域改造成同域
3)(前端)將JSON升級成JSONP,,JSONP 的原理很簡單,就是利用 < script> 標籤沒有跨域限制的漏洞。通過 < script>
標籤指向一個需要訪問的地址並提供一個回調函數來接收數據當需要通訊時。
JSONP 使用簡單且兼容性不錯,但是隻限於 get 請求。(缺點)
JSONP案例:
兩個網站A,和B,其中B通過jsonp接口向外提供職位查詢功能,A網站通過該jsonp接口向B發起職位查詢數據。
首先創建一個查詢表單頁面,即search.html
<script>
var url='https://www.phpmianshi.com/index.php?r=index/jsonp';
$("#dian").click(function(){
var zhi=$("#val").val();
var data={zhi:zhi};//搜索值
$.get(url,data,function(msg){
//console.log(msg);
//alert(msg[0].p_name);
var html='職位:';
for (var i in msg) {
//將接到的jsonp數據進行遍歷
html+='<br /> '+msg[i].p_name;
};
$('#list').append(html);
},'jsonp')//指定數據爲jsonp
})
//下面的方法也可以 爲原生的ajax方法
/*$("#dian").click(function () {
var zhi=$("#val").val();
$.ajax({
url: url,
data:'zhi='+zhi,
dataType: "jsonp",
jsonpCallback: "aa",
success: function (msg) {
//console.log(data)
$('#list').append('職位:'+msg[0].p_name);
}
})
})*/
</script>
然後,創建一個接口
//jsonp 接口 查詢職位
public function actionJsonp()
{
header("Access-Control-Allow-Origin: *");//同源策略 跨域請求 頭設置
header('content-type:text/html;charset=utf8 ');
//獲取回調函數名
$jsoncallback = htmlspecialchars($_REQUEST['callback']);//把預定義的字符轉換爲 HTML 實體。
$zhi = htmlspecialchars($_REQUEST['zhi']);
$arr=yii::$app->db->createCommand("select * from position where p_name like :name",array(':name'=>"%$zhi%"))->queryAll();
$json_data=json_encode($arr);
//輸出jsonp格式的數據
echo $jsoncallback . "(" . $json_data . ")";
}
4) 對iframe跨域來說:H5提供了postMessage()的方法,可以在父子頁面進行通信(加分項)
這是由H5提出來的的API,IE8以上支持這個功能。
window.postMessage()
方法可以安全地實現跨源通信。window.postMessage()
方法被調用時,會在所有頁面腳本執行完畢之後,向目標窗口派發一個 MessageEvent 消息。
用法:postMessage(data,origin)
方法接受兩個參數data
: html5規範支持任意基本類型或可複製的對象,但部分瀏覽器只支持字符串,所以傳參時最好用JSON.stringify()序列化。origin
: 協議+主機+端口號,也可以設置爲"*",表示可以傳遞給任意窗口,如果要指定和當前窗口同源的話設置爲"/"。
例子:
1.)a.html:(https://domain1.phpmianshi.com/a.html)
<iframe id="iframe" src="https://domain2.phpmianshi.com/b.html" style="display:none;"></iframe><script>
var iframe = document.getElementById('iframe');
iframe.onload = function() {
var data = {
name: 'aym'
};
// 向domain2傳送跨域數據
iframe.contentWindow.postMessage(JSON.stringify(data), 'https://domain2.phpmianshi.com');
};
// 接受domain2返回數據
window.addEventListener('message', function(e) {
alert('data from domain2 ---> ' + e.data);
}, false);</script>
2.)b.html:(https://domain2.phpmianshi.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), 'https://domain1.phpmianshi.com');
}
}, false);</script>
5.webscoket協議跨域
WebSocket protocol是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通信,同時允許跨域通訊,是server push技術的一種很好的實現。
原生WebSocket API使用起來不太方便,我們使用Socket.io,它很好地封裝了webSocket接口,提供了更簡單、靈活的接口,也對不支持webSocket的瀏覽器提供了向下兼容。
WebSocket不會專門用來做跨域,而是作爲消息推送或者聊天等.