1. 程式人生 > >使用JSONP實現跨域請求

使用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) + ')'

請求抓包截圖 在這裡插入圖片描述