學習AJAX跨域獲取數據碰到這個問題,特此記錄。
理解跨域首先必須要了解同源策略。同源策略是瀏覽器上為安全性考慮實施的非常重要的安全策略。
同源是什么?
URL由協議、域名、端口和路徑組成,如果兩個URL的協議、域名和端口相同,則表示他們同源。
為什么需要同源?
假設從一個惡意網站打開支付寶或其他重要的頁面(通過window.open),如果沒有同源限制,惡意網頁上的javascript腳本就可以任意操作你打開的支付寶等網頁,這是極其危險的。
由於同源策略的限制,XmlHttpRequest只允許請求當前源(域名、協議、端口)的資源,當你試圖請求不同域的資源時,瀏覽器會發出如下警告。
如果我們真的需要跨域請求,該怎么做呢?
1)很明顯,根據瀏覽器提示,CORS頭缺少....這個CORS是什么東西?
跨域資源共享(CORS )是一種網絡瀏覽器的技術規范,它為Web服務器定義了一種方式,允許網頁從不同的域訪問其資源。而這種訪問是被同源策略所禁止的。CORS系統定義了一種瀏覽器和服務器交互的方式來確定是否允許跨域請求。 它是一個妥協,有更大的靈活性,但比起簡單地允許所有這些的要求來說更加安全。
簡而言之,CORS就是能實現跨域訪問的一種方法。只需要服務器響應頭Access-Control-Allow-Origin中含有發起請求的域,就可跨域獲取資源。
如圖,響應頭中Access-Control-Allow-Origin設置為*,意味着所有的域都可以訪問該資源。如果是自己的服務器,設置為具體的域即可。
這種方法雖然簡單,但需要通過服務器后台進行設置,如果沒有權限修改后台數據,就不能獲取到數據了。
2)jsonp
jsonp是json數據的一種使用方式。為什么通過jsonp就能跨域請求呢?
在寫平常的html中,我們發現,Web頁面上調用js文件時是不受跨域的影響,例如調用CDN。不僅如此,我們還發現凡是擁有”src”這個屬性的標簽都擁有跨域的能力(script,img..)。
因此我們可以利用這個特性,設置script標簽的src屬性為給定數據的URL,當發起請求時,讓服務器將數據裝入js腳本文件中並返回這個腳本文件,這樣客戶端就獲得了這一段數據。而其中的難點就在於怎樣把數據裝入js文件中。
它的原理其實是這樣的,首先在客戶端注冊一個回調函數,用來接收返回的數據。然后把函數名字傳給服務器。服務器將所需要的數據打包成JSON,通過字符串連接,把傳遞過來的函數名,JSON數據拼接成函數調用的形式。注意!這是一個js腳本文件,因此當該文件被客戶端加載時,會立即執行這個函數,相當於用函數把數據包裹着傳遞給客戶端。
下圖代碼是通過JSONP從百度獲取關鍵字信息的函數
//keyword為搜索框輸入的關鍵字 function getJson(keyword) { //cb為回調處理函數名,wd是輸入的關鍵字,其他參數不用理會 var url="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=" +keyword+"&json=1&p=3&cb=jsonCallback"; var sc = document.createElement('script');//動態創建script標簽 sc.src=encodeURI(url); //引用服務器加載的js代碼 document.body.appendChild(sc); //添加結點 sc.remove(); //執行完畢后馬上刪除 } //回調處理函數 function jsonCallback(obj) {
for(var tmp in obj) { console.log(result[tmp]) } }
輸入關鍵字"我",發送請求,查看百度服務器響應正文
可以發現它返回的就是一個函數調用,函數名是我們傳遞給服務器的參數,形參是JSON數據,這段代碼返回后會立即執行。
JQuery對jsonp進行了封裝,可以通過以下方式調用
//第一種
$.getJSON(url,function(value,status) { console.log(value); console.log(status) })
$.ajax({//第二種
type: "get", async: false, url: encodeURI(url), dataType: "jsonp",//如果寫為json 會生成一個隨機的函數名字替換掉URL中第二個? jsonp: "cb",//后台定義的回調函數標識符(一般默認為:callback) jsonpCallback: "jsonCallback",//自定義的jsonp回調函數名稱,默認為jQuery自動生成的隨機函數名 success: function(data,status){ console.log(data) }, error: function(){ alert('fail'); } });
關於同源策略
除了AJAX XMLHttpRequest請求,存在同源策略的地方還有:跨frame腳本,跨window腳本,cookie訪問。
但是Cookie中的同源只關注域名,忽略協議和端口。所以https://localhost:8080/和http://localhost:8081/的Cookie是共享的