使用jquery的jsonp如何發(fā)起跨域請(qǐng)求及其原理詳解
前言
本文主要給大家介紹的是關(guān)于jquery jsonp發(fā)起跨域請(qǐng)求及其原理的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹:
跨域的安全限制都是對(duì)瀏覽器端來(lái)說(shuō)的,服務(wù)器端是不存在跨域安全限制的。
瀏覽器的同源策略限制從一個(gè)源加載的文檔或腳本與來(lái)自另一個(gè)源的資源進(jìn)行交互。
如果協(xié)議,端口和主機(jī)對(duì)于兩個(gè)頁(yè)面是相同的,則兩個(gè)頁(yè)面具有相同的源,否則就是不同源的。
如果要在js里發(fā)起跨域請(qǐng)求,則要進(jìn)行一些特殊處理了?;蛘撸憧梢园颜?qǐng)求發(fā)到自己的服務(wù)端,再通過(guò)后臺(tái)代碼發(fā)起請(qǐng)求,再將數(shù)據(jù)返回前端。
這里講下使用jquery的jsonp如何發(fā)起跨域請(qǐng)求及其原理。
先看下準(zhǔn)備環(huán)境:兩個(gè)端口不一樣,構(gòu)成跨域請(qǐng)求的條件。
獲取數(shù)據(jù):獲取數(shù)據(jù)的端口為9090

請(qǐng)求數(shù)據(jù):請(qǐng)求數(shù)據(jù)的端口為8080

1、先看下直接發(fā)起ajax請(qǐng)求會(huì)怎么樣
下面是發(fā)起請(qǐng)求端的代碼:
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域測(cè)試</title>
<script src="js/jquery-1.7.2.js"></script>
<script>
$(document).ready(function () {
$("#btn").click(function () {
$.ajax({
url: 'http://localhost:9090/student',
type: 'GET',
success: function (data) {
$(text).val(data);
}
});
});
});
</script>
</head>
<body>
<input id="btn" type="button" value="跨域獲取數(shù)據(jù)" />
<textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>
請(qǐng)求的結(jié)果如下圖:可以看到跨域請(qǐng)求因?yàn)闉g覽器的同源策略被攔截了。

2、接下來(lái)看如何發(fā)起跨域請(qǐng)求。解決跨域請(qǐng)求的方式有很多,這里只說(shuō)一下jquery的jsop方式及其原理。
首先我們需要明白,在頁(yè)面上直接發(fā)起一個(gè)跨域的ajax請(qǐng)求是不可以的,但是,在頁(yè)面上引入不同域上的js腳本卻是可以的,就像你可以在自己的頁(yè)面上使用<img src=""> 標(biāo)簽來(lái)隨意顯示某個(gè)域上的圖片一樣。
比如我在8080端口的頁(yè)面上請(qǐng)求一個(gè)9090端口的圖片:可以看到直接通過(guò)src跨域請(qǐng)求是可以的。

3、那么看下如何使用<script src="">來(lái)完成一個(gè)跨域請(qǐng)求:
當(dāng)點(diǎn)擊"跨域獲取數(shù)據(jù)"的按鈕時(shí),添加一個(gè)<script>標(biāo)簽,用于發(fā)起跨域請(qǐng)求;注意看請(qǐng)求地址后面帶了一個(gè)callback=showData的參數(shù);
showData即是回調(diào)函數(shù)名稱,傳到后臺(tái),用于包裹數(shù)據(jù)。數(shù)據(jù)返回到前端后,就是showData(result)的形式,因?yàn)槭莝cript腳本,所以自動(dòng)調(diào)用showData函數(shù),而result就是showData的參數(shù)。
至此,我們算是跨域把數(shù)據(jù)請(qǐng)求回來(lái)了,但是比較麻煩,需要自己寫腳本發(fā)起請(qǐng)求,然后寫個(gè)回調(diào)函數(shù)處理數(shù)據(jù),不是很方便。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域測(cè)試</title>
<script src="js/jquery-1.7.2.js"></script>
<script>
//回調(diào)函數(shù)
function showData (result) {
var data = JSON.stringify(result); //json對(duì)象轉(zhuǎn)成字符串
$("#text").val(data);
}
$(document).ready(function () {
$("#btn").click(function () {
//向頭部輸入一個(gè)腳本,該腳本發(fā)起一個(gè)跨域請(qǐng)求
$("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
});
});
</script>
</head>
<body>
<input id="btn" type="button" value="跨域獲取數(shù)據(jù)" />
<textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>
服務(wù)端:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//數(shù)據(jù)
List<Student> studentList = getStudentList();
JSONArray jsonArray = JSONArray.fromObject(studentList);
String result = jsonArray.toString();
//前端傳過(guò)來(lái)的回調(diào)函數(shù)名稱
String callback = request.getParameter("callback");
//用回調(diào)函數(shù)名稱包裹返回?cái)?shù)據(jù),這樣,返回?cái)?shù)據(jù)就作為回調(diào)函數(shù)的參數(shù)傳回去了
result = callback + "(" + result + ")";
response.getWriter().write(result);
}
結(jié)果:

4、再來(lái)看jquery的jsonp方式跨域請(qǐng)求:
服務(wù)端代碼不變,js代碼如下:最簡(jiǎn)單的方式,只需配置一個(gè)dataType:'jsonp' ,就可以發(fā)起一個(gè)跨域請(qǐng)求。jsonp指定服務(wù)器返回的數(shù)據(jù)類型為jsonp格式,可以看發(fā)起的請(qǐng)求路徑,自動(dòng)帶了一個(gè)callback=xxx,xxx是jquery隨機(jī)生成的一個(gè)回調(diào)函數(shù)名稱。
這里的success就跟上面的showData一樣,如果有success函數(shù)則默認(rèn)success()作為回調(diào)函數(shù)。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域測(cè)試</title>
<script src="js/jquery-1.7.2.js"></script>
<script>
$(document).ready(function () {
$("#btn").click(function () {
$.ajax({
url: "http://localhost:9090/student",
type: "GET",
dataType: "jsonp", //指定服務(wù)器返回的數(shù)據(jù)類型
success: function (data) {
var result = JSON.stringify(data); //json對(duì)象轉(zhuǎn)成字符串
$("#text").val(result);
}
});
});
});
</script>
</head>
<body>
<input id="btn" type="button" value="跨域獲取數(shù)據(jù)" />
<textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>
效果:

再看看如何指定特定的回調(diào)函數(shù):第30行代碼
回調(diào)函數(shù)你可以寫到<script>下(默認(rèn)屬于window對(duì)象),或者指明寫到window對(duì)象里,看jquery源碼,可以看到j(luò)sonp調(diào)用回調(diào)函數(shù)時(shí),是調(diào)用的window.callback。
然后看調(diào)用結(jié)果,發(fā)現(xiàn),請(qǐng)求時(shí)帶的參數(shù)是:callback=showData;調(diào)用回調(diào)函數(shù)的時(shí)候,先調(diào)用了指定的showData,然后再調(diào)用了success。所以,success是返回成功后必定會(huì)調(diào)用的函數(shù),就看你怎么寫了。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域測(cè)試</title>
<script src="js/jquery-1.7.2.js"></script>
<script>
function showData (data) {
console.info("調(diào)用showData");
var result = JSON.stringify(data);
$("#text").val(result);
}
$(document).ready(function () {
// window.showData = function (data) {
// console.info("調(diào)用showData");
//
// var result = JSON.stringify(data);
// $("#text").val(result);
// }
$("#btn").click(function () {
$.ajax({
url: "http://localhost:9090/student",
type: "GET",
dataType: "jsonp", //指定服務(wù)器返回的數(shù)據(jù)類型
jsonpCallback: "showData", //指定回調(diào)函數(shù)名稱
success: function (data) {
console.info("調(diào)用success");
}
});
});
});
</script>
</head>
<body>
<input id="btn" type="button" value="跨域獲取數(shù)據(jù)" />
<textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>
效果圖:


再看看如何改變callback這個(gè)名稱:第23行代碼
指定callback這個(gè)名稱后,后臺(tái)也需要跟著更改。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域測(cè)試</title>
<script src="js/jquery-1.7.2.js"></script>
<script>
function showData (data) {
console.info("調(diào)用showData");
var result = JSON.stringify(data);
$("#text").val(result);
}
$(document).ready(function () {
$("#btn").click(function () {
$.ajax({
url: "http://localhost:9090/student",
type: "GET",
dataType: "jsonp", //指定服務(wù)器返回的數(shù)據(jù)類型
jsonp: "theFunction", //指定參數(shù)名稱
jsonpCallback: "showData", //指定回調(diào)函數(shù)名稱
success: function (data) {
console.info("調(diào)用success");
}
});
});
});
</script>
</head>
<body>
<input id="btn" type="button" value="跨域獲取數(shù)據(jù)" />
<textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>
后臺(tái)代碼:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//數(shù)據(jù)
List<Student> studentList = getStudentList();
JSONArray jsonArray = JSONArray.fromObject(studentList);
String result = jsonArray.toString();
//前端傳過(guò)來(lái)的回調(diào)函數(shù)名稱
String callback = request.getParameter("theFunction");
//用回調(diào)函數(shù)名稱包裹返回?cái)?shù)據(jù),這樣,返回?cái)?shù)據(jù)就作為回調(diào)函數(shù)的參數(shù)傳回去了
result = callback + "(" + result + ")";
response.getWriter().write(result);
}
效果圖:

最后看看jsonp是否支持POST方式:ajax請(qǐng)求指定POST方式
可以看到,jsonp方式不支持POST方式跨域請(qǐng)求,就算指定成POST方式,會(huì)自動(dòng)轉(zhuǎn)為GET方式;而后端如果設(shè)置成POST方式了,那就請(qǐng)求不了了。
jsonp的實(shí)現(xiàn)方式其實(shí)就是<script>腳本請(qǐng)求地址的方式一樣,只是ajax的jsonp對(duì)其做了封裝,所以可想而知,jsonp是不支持POST方式的。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跨域測(cè)試</title>
<script src="js/jquery-1.7.2.js"></script>
<script>
$(document).ready(function () {
$("#btn").click(function () {
$.ajax({
url: "http://localhost:9090/student",
type: "POST", //post請(qǐng)求方式
dataType: "jsonp",
jsonp: "callback",
success: function (data) {
var result = JSON.stringify(data);
$("#text").val(result);
}
});
});
});
</script>
</head>
<body>
<input id="btn" type="button" value="跨域獲取數(shù)據(jù)" />
<textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>
效果圖:


再補(bǔ)充一點(diǎn),回到第一條:CORS頭缺少“Access-Control-Allow-Origin” 。
有時(shí)候你會(huì)發(fā)現(xiàn)其它都沒(méi)問(wèn)題,出現(xiàn)這個(gè)錯(cuò)誤:這個(gè)錯(cuò)誤代表服務(wù)端拒絕跨域訪問(wèn)。如果出現(xiàn)這個(gè)錯(cuò)誤,就需要在服務(wù)端設(shè)置允許跨域請(qǐng)求。
response.setHeader("Access-Control-Allow-Origin", "*"); 設(shè)置允許任何域名跨域訪問(wèn)

設(shè)置可以跨域訪問(wèn):第6行代碼或第8行代碼,設(shè)置其中一個(gè)即可。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// * 表示允許任何域名跨域訪問(wèn)
response.setHeader("Access-Control-Allow-Origin", "*");
// 指定特定域名可以訪問(wèn)
response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080/");
//數(shù)據(jù)
List<Student> studentList = getStudentList();
JSONArray jsonArray = JSONArray.fromObject(studentList);
String result = jsonArray.toString();
//前端傳過(guò)來(lái)的回調(diào)函數(shù)名稱
String callback = request.getParameter("callback");
//用回調(diào)函數(shù)名稱包裹返回?cái)?shù)據(jù),這樣,返回?cái)?shù)據(jù)就作為回調(diào)函數(shù)的參數(shù)傳回去了
result = callback + "(" + result + ")";
response.getWriter().write(result);
}
總結(jié)
jQuery ajax方式以jsonp類型發(fā)起跨域請(qǐng)求,其原理跟<script>腳本請(qǐng)求一樣,因此使用jsonp時(shí)也只能使用GET方式發(fā)起跨域請(qǐng)求??缬蛘?qǐng)求需要服務(wù)端配合,設(shè)置callback,才能完成跨域請(qǐng)求。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- 輕松搞定jQuery+JSONP跨域請(qǐng)求的解決方案
- 原生js jquery ajax請(qǐng)求以及jsonp的調(diào)用方法
- 關(guān)于jQuery.ajax()的jsonp碰上post詳解
- jQuery使用JSONP實(shí)現(xiàn)跨域獲取數(shù)據(jù)的三種方法詳解
- jQuery中JSONP的兩種實(shí)現(xiàn)方式詳解
- 淺談JQuery+ajax+jsonp 跨域訪問(wèn)
- 解決jQuery使用JSONP時(shí)產(chǎn)生的錯(cuò)誤
- 用jQuery與JSONP輕松解決跨域訪問(wèn)的問(wèn)題
- jquery ajax jsonp跨域調(diào)用實(shí)例代碼
- jQuery使用jsonp實(shí)現(xiàn)百度搜索的示例代碼
相關(guān)文章
jquery和javascript中如何將一元素的內(nèi)容賦給另一元素
將一元素的內(nèi)容賦給另一元素,在某些情況下還是比較實(shí)用的,下面為大家講解下jquery和javascript中是如何實(shí)現(xiàn)的2014-01-01
jQuery EasyUI開(kāi)發(fā)技巧總結(jié)
這篇文章主要介紹了jQuery EasyUI開(kāi)發(fā)技巧總結(jié)的相關(guān)資料,希望通過(guò)本文大家能夠掌握EasyUI的開(kāi)發(fā)技巧,需要的朋友可以參考下2017-09-09
基于jquery實(shí)現(xiàn)頁(yè)面滾動(dòng)時(shí)頂部導(dǎo)航顯示隱藏
這篇文章主要介紹了基于jquery實(shí)現(xiàn)頁(yè)面滾動(dòng)時(shí)頂部導(dǎo)航顯示隱藏效果,當(dāng)頁(yè)面向下滾動(dòng)的時(shí)候,導(dǎo)航菜單動(dòng)態(tài)隱藏,頁(yè)面滾動(dòng)到頂部時(shí),導(dǎo)航菜單動(dòng)態(tài)顯示,淘寶也采用過(guò)此效果,感興趣的小伙伴們可以參考一下2015-11-11
jQuery實(shí)現(xiàn)復(fù)選框批量選擇與反選的方法
這篇文章主要介紹了jQuery實(shí)現(xiàn)復(fù)選框批量選擇與反選的方法,主要通過(guò)jQuery的attr與removeAttr方法實(shí)現(xiàn)選擇與反選的功能,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-06-06
jquery實(shí)現(xiàn)彈出層遮罩效果的簡(jiǎn)單實(shí)例
這篇文章主要介紹了jquery實(shí)現(xiàn)彈出層遮罩效果的簡(jiǎn)單實(shí)例。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-03-03
jQuery中parents()和parent()的區(qū)別分析
這篇文章主要介紹了jQuery中parents()和parent()的區(qū)別,具體分析了parents()和parent()的原理與用法區(qū)別,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10

