使用jquery的jsonp如何發(fā)起跨域請求及其原理詳解
前言
本文主要給大家介紹的是關(guān)于jquery jsonp發(fā)起跨域請求及其原理的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹:
跨域的安全限制都是對瀏覽器端來說的,服務(wù)器端是不存在跨域安全限制的。
瀏覽器的同源策略限制從一個源加載的文檔或腳本與來自另一個源的資源進(jìn)行交互。
如果協(xié)議,端口和主機(jī)對于兩個頁面是相同的,則兩個頁面具有相同的源,否則就是不同源的。
如果要在js里發(fā)起跨域請求,則要進(jìn)行一些特殊處理了?;蛘撸憧梢园颜埱蟀l(fā)到自己的服務(wù)端,再通過后臺代碼發(fā)起請求,再將數(shù)據(jù)返回前端。
這里講下使用jquery的jsonp如何發(fā)起跨域請求及其原理。
先看下準(zhǔn)備環(huán)境:兩個端口不一樣,構(gòu)成跨域請求的條件。
獲取數(shù)據(jù):獲取數(shù)據(jù)的端口為9090
請求數(shù)據(jù):請求數(shù)據(jù)的端口為8080
1、先看下直接發(fā)起ajax請求會怎么樣
下面是發(fā)起請求端的代碼:
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>跨域測試</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>
請求的結(jié)果如下圖:可以看到跨域請求因為瀏覽器的同源策略被攔截了。
2、接下來看如何發(fā)起跨域請求。解決跨域請求的方式有很多,這里只說一下jquery的jsop方式及其原理。
首先我們需要明白,在頁面上直接發(fā)起一個跨域的ajax請求是不可以的,但是,在頁面上引入不同域上的js腳本卻是可以的,就像你可以在自己的頁面上使用<img src="">
標(biāo)簽來隨意顯示某個域上的圖片一樣。
比如我在8080端口的頁面上請求一個9090端口的圖片:可以看到直接通過src跨域請求是可以的。
3、那么看下如何使用<script src="">來完成一個跨域請求:
當(dāng)點擊"跨域獲取數(shù)據(jù)"的按鈕時,添加一個<script>標(biāo)簽,用于發(fā)起跨域請求;注意看請求地址后面帶了一個callback=showData
的參數(shù);
showData即是回調(diào)函數(shù)名稱,傳到后臺,用于包裹數(shù)據(jù)。數(shù)據(jù)返回到前端后,就是showData(result)
的形式,因為是script腳本,所以自動調(diào)用showData函數(shù),而result就是showData的參數(shù)。
至此,我們算是跨域把數(shù)據(jù)請求回來了,但是比較麻煩,需要自己寫腳本發(fā)起請求,然后寫個回調(diào)函數(shù)處理數(shù)據(jù),不是很方便。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>跨域測試</title> <script src="js/jquery-1.7.2.js"></script> <script> //回調(diào)函數(shù) function showData (result) { var data = JSON.stringify(result); //json對象轉(zhuǎn)成字符串 $("#text").val(data); } $(document).ready(function () { $("#btn").click(function () { //向頭部輸入一個腳本,該腳本發(fā)起一個跨域請求 $("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(); //前端傳過來的回調(diào)函數(shù)名稱 String callback = request.getParameter("callback"); //用回調(diào)函數(shù)名稱包裹返回數(shù)據(jù),這樣,返回數(shù)據(jù)就作為回調(diào)函數(shù)的參數(shù)傳回去了 result = callback + "(" + result + ")"; response.getWriter().write(result); }
結(jié)果:
4、再來看jquery的jsonp方式跨域請求:
服務(wù)端代碼不變,js代碼如下:最簡單的方式,只需配置一個dataType:'jsonp'
,就可以發(fā)起一個跨域請求。jsonp指定服務(wù)器返回的數(shù)據(jù)類型為jsonp格式,可以看發(fā)起的請求路徑,自動帶了一個callback=xxx
,xxx是jquery隨機(jī)生成的一個回調(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>跨域測試</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對象轉(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對象),或者指明寫到window對象里,看jquery源碼,可以看到j(luò)sonp調(diào)用回調(diào)函數(shù)時,是調(diào)用的window.callback
。
然后看調(diào)用結(jié)果,發(fā)現(xiàn),請求時帶的參數(shù)是:callback=showData;
調(diào)用回調(diào)函數(shù)的時候,先調(diào)用了指定的showData,然后再調(diào)用了success。所以,success是返回成功后必定會調(diào)用的函數(shù),就看你怎么寫了。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>跨域測試</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這個名稱:第23行代碼
指定callback這個名稱后,后臺也需要跟著更改。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>跨域測試</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>
后臺代碼:
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(); //前端傳過來的回調(diào)函數(shù)名稱 String callback = request.getParameter("theFunction"); //用回調(diào)函數(shù)名稱包裹返回數(shù)據(jù),這樣,返回數(shù)據(jù)就作為回調(diào)函數(shù)的參數(shù)傳回去了 result = callback + "(" + result + ")"; response.getWriter().write(result); }
效果圖:
最后看看jsonp是否支持POST方式:ajax請求指定POST方式
可以看到,jsonp方式不支持POST方式跨域請求,就算指定成POST方式,會自動轉(zhuǎn)為GET方式;而后端如果設(shè)置成POST方式了,那就請求不了了。
jsonp的實現(xiàn)方式其實就是<script>
腳本請求地址的方式一樣,只是ajax的jsonp對其做了封裝,所以可想而知,jsonp是不支持POST方式的。
<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>跨域測試</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請求方式 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ǔ)充一點,回到第一條:CORS頭缺少“Access-Control-Allow-Origin”
。
有時候你會發(fā)現(xiàn)其它都沒問題,出現(xiàn)這個錯誤:這個錯誤代表服務(wù)端拒絕跨域訪問。如果出現(xiàn)這個錯誤,就需要在服務(wù)端設(shè)置允許跨域請求。
response.setHeader("Access-Control-Allow-Origin", "*");
設(shè)置允許任何域名跨域訪問
設(shè)置可以跨域訪問:第6行代碼或第8行代碼,設(shè)置其中一個即可。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); // * 表示允許任何域名跨域訪問 response.setHeader("Access-Control-Allow-Origin", "*"); // 指定特定域名可以訪問 response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080/"); //數(shù)據(jù) List<Student> studentList = getStudentList(); JSONArray jsonArray = JSONArray.fromObject(studentList); String result = jsonArray.toString(); //前端傳過來的回調(diào)函數(shù)名稱 String callback = request.getParameter("callback"); //用回調(diào)函數(shù)名稱包裹返回數(shù)據(jù),這樣,返回數(shù)據(jù)就作為回調(diào)函數(shù)的參數(shù)傳回去了 result = callback + "(" + result + ")"; response.getWriter().write(result); }
總結(jié)
jQuery ajax方式以jsonp類型發(fā)起跨域請求,其原理跟<script>腳本請求一樣,因此使用jsonp時也只能使用GET方式發(fā)起跨域請求??缬蛘埱笮枰?wù)端配合,設(shè)置callback,才能完成跨域請求。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- 輕松搞定jQuery+JSONP跨域請求的解決方案
- 原生js jquery ajax請求以及jsonp的調(diào)用方法
- 關(guān)于jQuery.ajax()的jsonp碰上post詳解
- jQuery使用JSONP實現(xiàn)跨域獲取數(shù)據(jù)的三種方法詳解
- jQuery中JSONP的兩種實現(xiàn)方式詳解
- 淺談JQuery+ajax+jsonp 跨域訪問
- 解決jQuery使用JSONP時產(chǎn)生的錯誤
- 用jQuery與JSONP輕松解決跨域訪問的問題
- jquery ajax jsonp跨域調(diào)用實例代碼
- jQuery使用jsonp實現(xiàn)百度搜索的示例代碼
相關(guān)文章
jquery 模擬類搜索框自動完成搜索提示功能(改進(jìn))
改進(jìn)版,支持多個輸入框!前面因為多個輸入框信息不好保存所以只能支持一個,現(xiàn)在用輸入框的alt屬性來保存修改前的內(nèi)容,所以能支持多個輸入框了.初步測試沒發(fā)現(xiàn)問題,歡迎大家一起測試改進(jìn)!!!2010-05-05深入解析jQuery中Deferred的deferred.promise()方法
這篇文章主要介紹了jQuery中Deferred的deferred.promise()方法,提醒千萬要注意deferred.promise()與jQuery的.promise() 實例方法的區(qū)別,需要的朋友可以參考下2016-05-05jQuery在vs2008及js文件中的無智能提示的解決方法
我通過下面方法實現(xiàn)了jQuery在VS2008及js文件中的智能提示的,希望對朋友們有所幫助。2010-12-12jQuery EasyUI API 中文幫助文檔和擴(kuò)展實例
這篇文章主要介紹了jQuery EasyUI API 中文幫助文檔和擴(kuò)展實例 的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-08-08jQuery基于xml格式數(shù)據(jù)實現(xiàn)模糊查詢及分頁功能的方法
這篇文章主要介紹了jQuery基于xml格式數(shù)據(jù)實現(xiàn)模糊查詢及分頁功能的方法,涉及jQuery使用ajax技術(shù)針對xml格式數(shù)據(jù)的讀取、模糊查詢及分頁顯示等相關(guān)操作技巧,需要的朋友可以參考下2016-12-12html5以及jQuery實現(xiàn)本地圖片上傳前的預(yù)覽代碼實例講解
這篇文章主要介紹了html5以及jQuery實現(xiàn)本地圖片上傳前的預(yù)覽代碼實例講解,圖文代碼實例講解的很清晰,有感興趣的同學(xué)可以研究下2021-03-03