由于瀏覽器存在同源策略機制,同源策略阻止從一個源加載的文檔或腳本獲取或設置另一個源加載的文檔的屬性。
同源策略的判定規則:
如果兩個頁面擁有相同的協議,端口,和主機,那么這兩個頁面就屬于同一個源;
圖示例:
特別的:由于同源策略是瀏覽器的限制,所以請求的發送和響應是可以進行,只不過瀏覽器不接受罷了。
瀏覽器同源策略并不是對所有的請求均制約:
- 制約: XmlHttpRequest
- 無效: img、iframe、script等具有src屬性的標簽
兩種實現跨域請求的方式,JSONP和CORS
對比:
Jsonp只支持 GET 請求,CORS支持所有類型的HTTP請求。
Jsonp 的優勢在于支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。
(1) JSON-P實現跨域請求
利用script標簽的src屬性(瀏覽器允許script標簽跨域)。
基本原理:
- 瀏覽器創建script標簽,并利用script標簽的src屬性發送跨域請求,獲取服務器的返回值在<script>標簽內。
- 服務器返回函數調用語句(myfunc(args);),并將需要返回的值(args)作為函數參數一并返回。
- 瀏覽器執行服務器返回的調用函數的語句(myfunc(args)),對返回值進行操作。
- 瀏覽器刪除第一步創建的script標簽。
代碼實例:
<p>
<input type="button" onclick="getJsonp();" value='提交'/>
</p>
JS實現:
//創建script標簽跨域請求
function getJsonp(){
var tag = document.createElement('script');
tag.src = "http://tkq2.com:8000/test";
document.head.appendChild(tag);
document.head.removeChild(tag);
}
//根據返回函數myfunc([1,2,3]);執行定義的myfunc函數
function myfunc(list) {
console.log(list);
}
Jquery實現:
//創建script標簽跨域請求
function getJsonp(){
$.ajax({
url: "http://tkq2.com:8000/test",
dataType: 'jsonp',
jsonpCallback: 'myfunc'
})
}
其中jsonpCallback,自定義了回調函數名,默認為jQuery自動生成的隨機函數名。如果不寫回調函數名,默認執行與服務器返回的函數名相同的函數。
//根據返回函數myfunc([1,2,3]);執行定義的myfunc函數
function myfunc(list) {
console.log(list);
}
以上兩種寫法中,回調函數被服務端寫死了,請求端必須定義和服務器端相同函數名才行。但作為服務端應該有更好的兼容性,請求端自行決定回調函數名字。
JS實現:
//創建script標簽跨域請求,并根據返回函數myfunc([1,2,3]);執行定義的myfunc函數
function GetJsonp(){
var tag = document.createElement('script');
//自定義回調函數名,jsonpcallback=myfunc字段供服務端讀取。
tag.src = "http://tkq2.com:8000/test?jsonpcallback=myfunc";
document.head.appendChild(tag);
document.head.removeChild(tag);
}
function myfunc(list) {
console.log(list);
}
Jquery實現
//創建script標簽跨域請求,并根據返回函數myfunc([1,2,3]);執行定義的myfunc函數
function GetJsonp(){
$.ajax({
url: "http://tkq2.com:8000/test",
dataType: 'jsonp',
jsonp:'jsonpcallback', //傳遞給請求處理程序或頁面的,用以獲得jsonp回調函數名的參數名(一般默認為:callback)
jsonpCallback:'myfunc' //自定義了回調函數名,默認為jQuery自動生成的隨機函數名。如果不寫回調函數名,默認執行與服務器返回的函數名相同的函數。
})
}
//回調函數
function myfunc(list) {
console.log(list);
}
(2) CORS跨域資源共享
隨著技術的發展,現在的瀏覽器可以支持主動設置從而允許跨域請求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質是設置響應頭,使得瀏覽器允許跨域請求。
這種實現方式:請求端和普通的AJAX方法相同,但服務器端需要做相應的配置。
跨域傳輸cookie:
在跨域請求中,默認情況下,HTTP Authentication信息,Cookie頭以及用戶的SSL證書無論在預檢請求中或是在實際請求都是不會被發送。
如果想要發送:
瀏覽器端:XMLHttpRequest的 withCredentials 為 true (如果后臺需要傳cookie,則設置,否則,不用設置)
服務器端:Access-Control-Allow-Credentials 為 true
$.ajax({
url: ajaxUrlConfig.getAddOrder,
data: data,
type: 'POST',
xhrFields: {
withCredentials: true
},
dataType: 'json',
timeout: 300000
});