這篇文章主要為大家展示了“Jsonp如何解決ajax跨域問題”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Jsonp如何解決ajax跨域問題”這篇文章吧。
成都創(chuàng)新互聯(lián)提供高防服務(wù)器、云服務(wù)器、香港服務(wù)器、四川移動機(jī)房托管等
一、介紹
最近跨域問題比較多,而且自己剛好也看到這一塊,就總結(jié)了一下,關(guān)于JSONP的東西百度的話東西確實(shí)很多,很多人都是復(fù)制別人的,如此下去,其實(shí)找的資料就那么幾份,關(guān)鍵是我還看不懂,可能是能力問題吧,自己經(jīng)過很多嘗試,所以總結(jié)了一下,終究還是弄懂了皮毛。注意一點(diǎn)是,這里是用Jsonp解決ajax的跨域問題,具體的實(shí)現(xiàn)其實(shí)不是ajax。
1、同源策略
瀏覽器有一個很重要的概念——同源策略(Same-Origin Policy)。所謂同源是指,域名,協(xié)議,端口相同。不同源的客戶端腳本(JavaScript、ActionScript)在沒明確授權(quán)的情況下,不能讀寫對方的資源。
2、JSONP
JSONP(JSON with Padding)是JSON的一種”使用模式”,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題。由于同源策略,一般來說位于 server1.example.com 的網(wǎng)頁無法與不是 server1.example.com的服務(wù)器溝通,而 HTML 的script 元素是一個例外。利用 <script> 元素的這個開放策略,網(wǎng)頁可以得到從其他來源動態(tài)產(chǎn)生的 JSON 資料,而這種使用模式就是所謂的 JSONP。用 JSONP 抓到的資料并不是 JSON,而是任意的JavaScript,用 JavaScript 直譯器執(zhí)行而不是用 JSON 解析器解析。
二、實(shí)踐
1、模擬跨域請求
在本機(jī)弄兩個tomcat,端口分別為8080,8888,也就滿足了非同源的條件,那么要是從一個端口發(fā)送ajax去獲取另外一個端口的數(shù)據(jù),那么肯定會報跨域請求問題。
這里有兩個項(xiàng)目,分別是jsonp(8080),other(8888),在jsonp項(xiàng)目中index.jsp如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Insert title here</title> <script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript"> function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/index.jsp', type:'post', dataType:'text', success:function(data){ console.log(data); } }); } </script> </head> <body> <input type="button" value="jsonp" onclick="jsonp_fun()"/> </body> </html>
other(8888)項(xiàng)目中index.jsp如下:// 因?yàn)閖sp實(shí)際就是servlet,這里就用jsp代替servlet演示。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Insert title here</title> <script type="text/javascript" src="js/jquery.min.js"></script> </head> <body> other domain </body> </html>
其實(shí)中上面看無非就是jsonp頁面中點(diǎn)擊按鈕ajax去獲取other頁面中的數(shù)據(jù)。
結(jié)果如下:chrome控制臺
XMLHttpRequest cannot load http://localhost:8888/other/index.jsp. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
以上提示就是指跨域問題,不能從8080這個域去訪問8888域的資源。
2、利用script標(biāo)簽去訪問other域的js文件
由于<script>標(biāo)簽的src是支持跨域請求的。最常見的就是cdn服務(wù)的應(yīng)用啦,比如我項(xiàng)目中,如果想用jQuery,但是就沒有這個js文件,去下載要找很久,而且版本還不知道下的對不對,那么可以百度搜jquery cdn,我隨便找一個,比如bootstrap的cdn:http://www.bootcdn.cn/jquery/,有很多版本供你選擇,只要在項(xiàng)目中加上就行了,最大缺點(diǎn)的話就是你沒網(wǎng)的話,就引入不到啦。
2.1 在other根路徑創(chuàng)建js/other.js文件,內(nèi)容如下:
alert("this is other(8888) js");
2.2 在jsonp/index.jsp中,加入script標(biāo)簽,引入other的js
<script type="text/javascript" src="http://localhost:8888/other/js/other.js"></script>
進(jìn)入http://localhost:8080/jsonp/index.jsp,會立馬彈出alert,表示引入的js文件自動執(zhí)行了,跨域請求js成功。
2.3 同樣的,直接引用,會立馬執(zhí)行立馬的alert,那么在other.js中寫函數(shù),同樣jsonp/index.jsp中也能調(diào)用到,這點(diǎn)就不演示了,項(xiàng)目開發(fā)中大多都是這樣做的,頁面與js/css分離。
2.4 另外說明一點(diǎn),如果在other.js中有函數(shù)通過ajax調(diào)用8080中的東西,然后引入之后,調(diào)用這個函數(shù),也是可以的,但是如果other.js中函數(shù)ajax調(diào)用8888的東西,引入之后,調(diào)用這個函數(shù),同樣是跨域的。
3、script實(shí)現(xiàn)跨域請求
3.1 簡單模擬服務(wù)器返回數(shù)據(jù)
將jsonp/index.jsp改成如下:這里注意引入的other.js的位置,是在函數(shù)getResult之后的,如果在它之前的話,會提示函數(shù)不存在。js加載順序是從上開始,在之前調(diào)用沒創(chuàng)建的,不能成功。注意這里是指引入的js文件,如果是同一個js文件或者當(dāng)前頁面的js中,先執(zhí)行調(diào)用,然后再寫函數(shù)也是沒有問題的,但是如果先執(zhí)行調(diào)用引入js文件中的函數(shù),然后再引入js文件,就會提示函數(shù)不存在。
<script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript"> function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/index.jsp', type:'post', dataType:'text', success:function(data){ console.log(data); } }); } function getResult(data){ alert(data.result); } </script> <script type="text/javascript" src="http://localhost:8888/other/js/other.js"></script>
然后other.js
getResult({"result":"this is other domain's data"});
也就是在jsonp/index.jsp頁面寫好函數(shù),然后引入其他域的js傳入?yún)?shù)去調(diào)用這個函數(shù),這里的參數(shù)你可以先看做是其他域服務(wù)器的接口返回的數(shù)據(jù)。
刷新頁面,效果當(dāng)然是
彈出alert框,this is other domain's data
3.2 模擬接口訪問
看到這里,你會不會還是想不懂,上面js弄啥的,傳個死的數(shù)據(jù),有什么實(shí)際意義嗎?,其實(shí)script的src不僅可以接js的地址,還可以接servlet的地址,也就是http接口地址,所以接下來,懶得寫servlet,這里還是寫jsp當(dāng)做接口,在other項(xiàng)目中新建other.jsp頁面,內(nèi)容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String params = request.getParameter("params"); out.println("ajax cross success,the server receive params :"+params); %>
內(nèi)容很簡單,也就是接受一個params的參數(shù),然后返回數(shù)據(jù)給調(diào)用者。
我們在jsonp/index.jsp中加上
<script type="text/javascript" src="http://localhost:8888/other/other.jsp?params=fromjsonp"></script>
看到這個地址,你是不是很熟悉,不熟悉的證明你用servlet用蠢了,jsp也是servlet,流程就是頁面一加載的時候,script標(biāo)簽就會去發(fā)送請求,然后返回數(shù)據(jù)。那么我們刷新頁面,看看效果。
Uncaught SyntaxError: Unexpected identifier
報錯了,如上,然后代碼有問題?No,點(diǎn)擊錯誤,你會看到請求的東西也打印出來了,就是提示錯誤,表示這個東西瀏覽器不認(rèn)識,其實(shí)是script不認(rèn)識啦。
還不明白,那么你去頁面加上如下內(nèi)容,你看報不報錯??!肯定報錯
<script type="text/javascript"> ajax cross success,the server receive params : jsonp_param </script>
那么js不能解析,我們換一種思路,要是我們輸出的是JSON字符串或者調(diào)用當(dāng)前頁面函數(shù)的字符串了,類似于3.1中返回的getResult({“result”:”this is other domain's data”});
所以改造一下,把other.jsp中的內(nèi)容改成
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String params = request.getParameter("params"); //out.println("ajax cross success,the server receive params :"+params); out.println("getResult({'result':'"+params+"'})"); %>
別忘了,之前jsonp/index.jsp中我們定義了,那么加入引用之后,依然記得getResult函數(shù)與引入函數(shù)的先后順序問題。
<script type="text/javascript"> function getResult(data){ alert(data.result); } </script> <script type="text/javascript" src="http://localhost:8888/other/other.jsp?params=fromjsonp"></script>
刷新頁面,發(fā)現(xiàn)大工告成。
至此,大部分原理已經(jīng)講完了,還有一個問題,這里服務(wù)器返回的是getResult(xxx),其中這里的xxx可以當(dāng)做是經(jīng)過接口的很多處理,然后塞進(jìn)去的值,但是這個getResult這個函數(shù)名,調(diào)用方與其他域服務(wù)器這一方怎么約定這個名字是一致的了,況且很多公司自己做服務(wù)的,別的公司的開發(fā)人員去調(diào)用,難道每個人都去那么公司去約定調(diào)用函數(shù)的名字?怎么可能,所以有人就想出來了一種解決方案,當(dāng)然不是我~~,其實(shí)也很簡單啦,也就是把回調(diào)的函數(shù)名字也一起傳過去不就行了,所以代碼如下:
<script type="text/javascript" src="http://localhost:8888/other/other.jsp?params=fromjsonp&callback=getResult"></script>
other.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String params = request.getParameter("params"); String callback = request.getParameter("callback"); // 經(jīng)過該接口一系列操作,然后得到data,將data返回給調(diào)用者 String data = "{'result':'"+params+"'}"; out.println(callback + "("+data+")"); %>
代碼很簡單,也就是傳遞一個回調(diào)函數(shù)的參數(shù)名,然后經(jīng)過該接口一系列操作,將返回數(shù)據(jù),塞到回調(diào)函數(shù)里面,調(diào)用端的函數(shù)就得到了該接口的數(shù)據(jù),也就是類似于ajax中succsss:function(data),然后處理data一樣,這里的success回調(diào)函數(shù),相當(dāng)于上面的getResult函數(shù)。當(dāng)然你也可以寫的優(yōu)雅一點(diǎn),比如:
function CreateScript(src) { $("<script><//script>").attr("src", src).appendTo("body") } function jsonp_fun(){ CreateScript("http://localhost:8888/other/other.jsp?params=fromjsonp&callback=getResult") }
4、Jquery的JSONP
至此跨域請求的原理已經(jīng)講清楚了,但是仍然還有一個問題,總覺得這樣用有點(diǎn)怪是不是,如果用jquery的話,調(diào)用就很簡單了,其實(shí)jquery底層實(shí)現(xiàn)也是拼了一個script,然后指定src這種方式,跟上面講的一樣,只是jquery封裝了一下,顯得更加優(yōu)雅,跟ajax調(diào)用方式差不多,所以容易記,代碼如下:
<script type="text/javascript"> function getResult(data){ alert("through jsonp,receive data from other domain : "+data.result); } function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/other.jsp', type:'post', data:{'params':'fromjsonp'}, dataType: "jsonp", jsonp: "callback",//傳遞給請求處理程序或頁面的,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(一般默認(rèn)為:callback) jsonpCallback:"getResult",//自定義的jsonp回調(diào)函數(shù)名稱,默認(rèn)為jQuery自動生成的隨機(jī)函數(shù)名,也可以不寫這個參數(shù),jQuery會自動為你處理數(shù)據(jù) success: function(data){ }, error: function(){ alert('fail'); } }); } </script> <body> <input type="button" value="jsonp" onclick="jsonp_fun()"/> </body>
這里的jsonCallback,回調(diào)函數(shù)設(shè)置為getResult,那么返回后會先調(diào)用getResult函數(shù)中的代碼,再調(diào)用success函數(shù)中的代碼,一般情況下,不用定義getResult函數(shù),同樣jsonCallback不需要設(shè)置,那么就只執(zhí)行success中的代碼,也就跟平時的ajax一樣用啦。
所以實(shí)際工作用法如下:
function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/other.jsp', type:'post', data:{'params':'fromjsonp'}, dataType: "jsonp", jsonp: "callback",//傳遞給請求處理程序或頁面的,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(一般默認(rèn)為:callback) success: function(data){ alert("through jsonp,receive data from other domain : "+data.result); }, error: function(){ alert('fail'); } }); } <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String params = request.getParameter("params"); String callback = request.getParameter("callback"); // 經(jīng)過該接口一系列操作,然后得到data,將data返回給調(diào)用者 String data = "{\"result\":\""+params+"\"}"; out.println(callback + "("+data+")"); %>
這里沒有指定jsonpCallback,實(shí)際上jquery底層拼裝了一個函數(shù)名,當(dāng)然生成函數(shù)規(guī)則就沒研究了。
補(bǔ)充:
1、ajax和jsonp這兩種技術(shù)在調(diào)用方式上“看起來”很像,目的也一樣,都是請求一個url,然后把服務(wù)器返回的數(shù)據(jù)進(jìn)行處理,因此jquery和ext等框架都把jsonp作為ajax的一種形式進(jìn)行了封裝;
2、但ajax和jsonp其實(shí)本質(zhì)上是不同的東西。ajax的核心是通過XmlHttpRequest獲取非本頁內(nèi)容,而jsonp的核心則是動態(tài)添加<script>標(biāo)簽來調(diào)用服務(wù)器提供的js腳本。
3、所以說,其實(shí)ajax與jsonp的區(qū)別不在于是否跨域,ajax通過服務(wù)端代理一樣可以實(shí)現(xiàn)跨域,jsonp本身也不排斥同域的數(shù)據(jù)的獲取。
4、還有就是,jsonp是一種方式或者說非強(qiáng)制性協(xié)議,如同ajax一樣,它也不一定非要用json格式來傳遞數(shù)據(jù),如果你愿意,字符串都行,只不過這樣不利于用jsonp提供公開服務(wù)。
以上是“Jsonp如何解決ajax跨域問題”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
當(dāng)前名稱:Jsonp如何解決ajax跨域問題
文章路徑:http://muchs.cn/article34/jcpepe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、ChatGPT、電子商務(wù)、搜索引擎優(yōu)化、云服務(wù)器、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)