使用JSONP實現跨域請求
實現跨域請求的常用方式
1、跨域請求只針對瀏覽器,而不針對服務端,因此可以先請求同源的服務端,然後由該服務端發出跨域請求,得到資料後再返回給瀏覽器。
2、在服務端程式的響應頭資訊中新增Access-Control-Allow-Origin
相關資訊。
3、使用<script>
來完成跨域請求,因為在頁面上引入不同域上的js指令碼是可以的,就像可以在頁面上使用<img>
標籤來引用不同域上的圖片一樣。
$(function() { $("#btn").on("click", function() { //向頭部輸入一個指令碼,該指令碼發起一個跨域請求 $("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>"); }); }); //自定義回撥函式,引數為返回的資料 function showData(result) { console.log(result); }
點選按鈕時,動態新增一個<script>
標籤,用於發起跨域請求,請求地址後面有一個callback=showData
引數。
showData
即為回撥函式名稱,會傳遞到後臺,用於包裹返回資料(注意:後臺不是直接返回資料)。
資料返回前端後,就是showData(result)
的形式,指令碼會自動呼叫回撥函式showData
,而result
就是showData
的引數。
4、使用JSONP(JSON with Padding),JSONP是一種常用的跨域手段,但只支援JS指令碼和JSON格式的資料。顧名思義,JSONP是利用JSON作為墊片,從而實現跨域請求的一種技術手段。其基本原理是利用HTML的
使用jQuery的jsonp
jQuery的Ajax物件支援JSONP方式的跨域請求,通過設定dataType: jsonp
即可實現。
JSONP需要服務端的支援,具體表現為返回的資料為callback(json_data)
的形式,即要返回回撥函式包裹JSON資料的形式,而不是直接返回JSON資料。否則,雖然前端可以獲取到請求資料,但不會執行ajax的成功回撥函式,而是執行請求失敗的回撥函式,錯誤資訊為200 load
。
//前端 $.ajax({ url: "http://cross-domain/get_data", dataType: "jsonp" //指定伺服器返回的資料型別 }).done(...).fail(...); //服務端Python @app.route('/get_data', methods=['GET']) def get_data(): resp_data = [{'name': '中文'}, {'name': 'English'}] # 獲取回撥函式名稱 callback = request.args.get('callback') # 支援JSONP,使用回撥函式包裹實際要返回的JSON資料 return callback + '(' + json.dumps(resp_data) + ')'
請求抓包截圖
實際請求的路徑,自動帶了一個callback=jQueryxxx
的引數,jQueryxxx
是隨機生成的一個回撥函式名稱。
自定義引數及回撥函式名稱
使用jQuery的Ajax請求中的以下兩個引數,來自定義JSONP的引數及回撥函式名稱:
- jsonp: 預設值為
callback
,即傳送到服務端的引數名稱。 - jsonpCallback: 自定義的回撥函式名稱,該函式定義在window物件下(實際上也可不進行定義,不會報錯),並在Ajax請求自身的回撥函式前進行呼叫。
//前端
//自定義回撥函式,引數為請求返回的資料
function handleData(resp_data) {
console.log("Data: ", resp_data);
}
//ajax請求
$.ajax({
url: "http://cross-domain/get_data",
dataType: "jsonp", //指定伺服器返回的資料型別
jsonp: "invoker", //指定引數名稱
jsonpCallback: "handleData" //指定回撥函式
}).done(function(resp_data) {
console.log("Ajax Done!");
}).fail(...);
//服務端,注意修改引數名稱
@app.route('/get_data', methods=['GET'])
def get_data():
resp_data = [{'name': '中文'}, {'name': 'English'}]
# 獲取回撥函式名稱
callback = request.args.get('invoker')
# 支援JSONP,使用回撥函式包裹實際要返回的JSON資料
return callback + '(' + json.dumps(resp_data) + ')'
請求抓包截圖