九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
深入剖析jsonp跨域原理
在項(xiàng)目中遇到一個(gè)jsonp跨域的問(wèn)題,于是仔細(xì)的研究了一番jsonp跨域的原理。搞明白了一些以前不是很懂的地方,比如:
1)jsonp跨域只能是get請(qǐng)求,而不能是post請(qǐng)求;
2)jsonp跨域的原理到底是什么;
3)除了jsonp跨域之外還有那些方法繞過(guò)“同源策略”,實(shí)現(xiàn)跨域訪問(wèn);
4)jsonp和ajax,或者說(shuō)jsonp和XMLHttpRequest是什么關(guān)系;
等等。
1.同源策略
說(shuō)到跨域,首先要明白“同源策略”。同源是指:js腳本只能訪問(wèn)或者請(qǐng)求相同協(xié)議,相同domain(網(wǎng)址/ip),相同端口的頁(yè)面。
我們知道,js腳本可以訪問(wèn)所在頁(yè)面的所有元素。通過(guò)ajax技術(shù),js也可以訪問(wèn)同一協(xié)議,同一個(gè)domain(ip),同一端口的服務(wù)器上的其他頁(yè)面,請(qǐng)求到瀏覽器端之后,利用js就可以進(jìn)行任意的訪問(wèn)。但是對(duì)于協(xié)議不同, 或者domain不同或者端口不同的服務(wù)器上的頁(yè)面就無(wú)能為力了,完全不能進(jìn)行請(qǐng)求。
下面在本地搭建兩個(gè)tomcat,分別將端口設(shè)為8080,和8888,進(jìn)行相關(guān)實(shí)驗(yàn)。顯然他們的端口是不同的。演示如下:
http://localhost:8888/html4/ajax.html的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="jsonp">
<meta name="description" content="jsonp">
<title>jsonp</title>
<style type="text/css">
*{margin:0;padding:0;}
a{display:inline-block;margin:50px 50px;}
</style>
</head>
<body>
<a href="javascript:;" onclick="myAjax();">click me</a>
<script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>
<script type="text/javascript">
function myAjax(){
var xmlhttp;
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = ActionXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
console.log(xmlhttp.responseText);
}
}
var url = "http://localhost:8080/minisns/json.jsp" + "?r=" + Math.random();
xmlhttp.open("Get", url, true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send();
}
</script>
</body>
</html>
這里為了結(jié)果不受其他js庫(kù)的干擾,使用了原生的XMLHttpRequest來(lái)處理,結(jié)果如下:
我們看到8080端口的js的ajax請(qǐng)求無(wú)法訪問(wèn)8888端口的頁(yè)面。原因是“同源策略不允許讀取”。
既然普通的ajax不能訪問(wèn),那么怎樣才能訪問(wèn)呢?大家都知道,使用jsonp啊,那jsonp的原理是什么呢?他為什么能跨域呢?
2.jsonp跨域的原理
我們知道,在頁(yè)面上有三種資源是可以與頁(yè)面本身不同源的。它們是:js腳本,css樣式文件,圖片,像taobao等大型網(wǎng)站,很定會(huì)將這些靜態(tài)資源放入cdn中,然后在頁(yè)面上連接,如下所示,所以它們是可以鏈接訪問(wèn)到不同源的資源的。
1)<script type="text/javascript" src="某個(gè)cdn地址" ></script>
2)<link type="text/css" rel="stylesheet" href="某個(gè)cdn地址" />
3)<img src="某個(gè)cdn地址" alt=""/>
而jsonp就是利用了<script>標(biāo)簽可以鏈接到不同源的js腳本,來(lái)到達(dá)跨域目的。當(dāng)鏈接的資源到達(dá)瀏覽器時(shí),瀏覽器會(huì)根據(jù)他們的類型來(lái)采取不同的處理方式,比如,如果是css文件,則會(huì)進(jìn)行對(duì)頁(yè)面 repaint,如果是img 則會(huì)將圖片渲染出來(lái),如果是script 腳本,則會(huì)進(jìn)行執(zhí)行,比如我們?cè)陧?yè)面引入了jquery庫(kù),為什么就可以使用 $ 了呢?就是因?yàn)?jquery 庫(kù)被瀏覽器執(zhí)行之后,會(huì)給全局對(duì)象window增加一個(gè)屬性: $ ,所以我們才能使用 $ 來(lái)進(jìn)行各種處理。(另外為什么要一般要加css放在頭部,而js腳本放在body尾部呢,就是為了減少repaint的次數(shù),另外因?yàn)閖s引擎是單線程執(zhí)行,如果將js腳本放在頭部,那么在js引擎在執(zhí)行js代碼時(shí),會(huì)造成頁(yè)面暫停。)
利用 頁(yè)面上 script 標(biāo)簽可以跨域,并且其 src 指定的js腳本到達(dá)瀏覽器會(huì)執(zhí)行的特性,我們可以進(jìn)行跨域取得數(shù)據(jù)。我們用一個(gè)例子來(lái)說(shuō)明:
8888端口的html4項(xiàng)目中的jsonp.html頁(yè)面代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="jsonp">
<meta name="description" content="jsonp">
<title>jsonp</title>
</head>
<body>
<script type="text/javascript" src="js/jquery-1.11.1.js"></script>
<script type="text/javascript">
var url = "http://localhost:8080/html5/jsonp_data.js";
// 創(chuàng)建script標(biāo)簽,設(shè)置其屬性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script標(biāo)簽加入head,此時(shí)調(diào)用開(kāi)始
document.getElementsByTagName('head')[0].appendChild(script);
function callbackFun(data)
{
console.log(data.age);
console.log(data.name);
}
</script>
</body>
</html>
其訪問(wèn)的8080端口的html5項(xiàng)目中的jsonp_data.js代碼如下:
1
callbackFun({"age":100,"name":"yuanfang"})
將兩個(gè)tomcate啟動(dòng),用瀏覽器訪問(wèn)8888端口的html4項(xiàng)目中的jsonp.html,結(jié)果如下:
上面我們看到,我們從8888 端口的頁(yè)面通過(guò) script 標(biāo)簽成功 的訪問(wèn)到了8080 端口下的jsonp_data.js中的數(shù)據(jù)。這就是 jsonp 的基本原理,利用script標(biāo)簽的特性,將數(shù)據(jù)使用json格式用一個(gè)函數(shù)包裹起來(lái),然后在進(jìn)行訪問(wèn)的頁(yè)面中定義一個(gè)相同函數(shù)名的函數(shù),因?yàn)?script 標(biāo)簽src引用的js腳本到達(dá)瀏覽器時(shí)會(huì)執(zhí)行,而我們有定義了一個(gè)同名的函數(shù),所以json格式的數(shù)據(jù),就做完參數(shù)傳遞給了我們定義的同名函數(shù)了。這樣就完成了跨域數(shù)據(jù)交換。jsonp的含義是:json with padding,而在json數(shù)據(jù)外包裹它的那個(gè)函數(shù),就是所謂的 padding 啦^--^
明白了原理之后,我們?cè)倏匆粋€(gè)更加實(shí)用的例子:
8080端口的html5項(xiàng)目中定義一個(gè)servlet:
package com.tz.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.alibaba.fastjson.JSON;@WebServlet("/JsonServlet")public class JsonServlet extends HttpServlet { private static final long serialVersionUID = 4335775212856826743L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String callbackfun = request.getParameter("mycallback"); System.out.println(callbackfun); // callbackFun response.setContentType("text/json;charset=utf-8"); User user = new User(); user.setName("yuanfang"); user.setAge(100); Object obj = JSON.toJSON(user); System.out.println(user); // com.tz.servlet.User@164ff87 System.out.println(obj); // {"age":100,"name":"yuanfang"} callbackfun += "(" + obj + ")"; System.out.println(callbackfun); // callbackFun({"age":100,"name":"yuanfang"}) response.getWriter().println(callbackfun); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); }}
在8888端口的html4項(xiàng)目中的jsonp.html來(lái)如下的跨域訪問(wèn)他:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="jsonp">
<meta name="description" content="jsonp">
<title>jsonp</title>
<style type="text/css">
*{margin:0;padding:0;}
div{width:600px;height:100px;margin:20px auto;}
</style>
</head>
<body>
<div>
<a href="javascript:;">jsonp測(cè)試</a>
</div>
<script type="text/javascript" src="js/jquery-1.11.1.js"></script>
<script type="text/javascript">
function callbackFun(data)
{
console.log(111);
console.log(data.name);
//data.age = 10000000;
//alert(0000);
}
$(function(){
$("a").on("click", function(){
$.ajax({
type:"post",
url:"http://localhost:8080/html5/JsonServlet",
dataType:'jsonp',
jsonp:'mycallback',
jsonpCallback:'callbackFun',
success:function(data) {
console.log(2222);
console.log(data.age);
}
});
})
});
</script>
</body>
</html>
結(jié)果如下:
我們看到,我們成功的跨域取到了servlet中的數(shù)據(jù),而且在我們指定的回調(diào)函數(shù)jsonpCallback:'callbackFun' 和 sucess 指定的回調(diào)函數(shù)中都進(jìn)行了執(zhí)行。而且總是callbackFun先執(zhí)行,如果我們打開(kāi)注釋://data.age = 10000000; //alert(0000);
就會(huì)發(fā)現(xiàn):在callbackFun中對(duì) data 進(jìn)行修改之后,success指定的回調(diào)函數(shù)的結(jié)果也會(huì)發(fā)生變化,而且通過(guò)alert(0000),我們確定了如果alert(000)沒(méi)有執(zhí)行完,success指定的函數(shù)就不會(huì)開(kāi)始執(zhí)行,就是說(shuō)兩個(gè)回調(diào)函數(shù)是先后同步執(zhí)行的。
結(jié)果如下:
3.jsonp 跨域與 ajax
從上面的介紹和例子,我們知道了 jsonp 跨域的原理,是利用了script標(biāo)簽的特性來(lái)進(jìn)行的,但是這和ajax有什么關(guān)系呢?顯然script標(biāo)簽加載js腳本和ajax一點(diǎn)關(guān)系都沒(méi)有,在沒(méi)有ajax技術(shù)之前,script標(biāo)簽就存在了的。只不過(guò)是jquery的封裝,使用了ajax來(lái)向服務(wù)器傳遞 jsonp 和 jsonpCallback 這兩個(gè)參數(shù)而已。我們服務(wù)器端和客戶端實(shí)現(xiàn)對(duì)參數(shù) jsonp 和 jsonpCallback 的值,協(xié)調(diào)好,那么就沒(méi)有必要使用ajax來(lái)傳遞著兩個(gè)參數(shù)了,就像上面第二個(gè)例子那樣,直接構(gòu)造一個(gè)script標(biāo)簽就行了。不過(guò)實(shí)際上,我們還是會(huì)使用ajax的封裝,因?yàn)樗谡{(diào)用完成之后,又將動(dòng)態(tài)添加的script標(biāo)簽去掉了,我們看下相關(guān)的源碼:
上面的代碼先構(gòu)造一個(gè)script標(biāo)簽,然后注冊(cè)一個(gè)onload的回調(diào),最后將構(gòu)造好的script標(biāo)簽insert進(jìn)去。insert完成之后,會(huì)觸發(fā)onload回調(diào),其中又將前面插入的script標(biāo)簽去掉了。其中的 代碼 callback( 200, "success" ) 其實(shí)就是觸發(fā) ajax 的jsonp成功時(shí)的success回調(diào)函數(shù),callback函數(shù)其實(shí)是一個(gè) done 函數(shù),其中包含了下面的代碼:
因?yàn)閭魅氲氖?200 ,所以 isSuccess = true; 所以執(zhí)行 "success"中的回調(diào)函數(shù),response = ajaxHandleResponse(...) 就是我們處理服務(wù)器servelt返回的數(shù)據(jù),我們可以調(diào)試:console.log(response.data.age); console.log(response.data.name); 看到結(jié)果。
3.jsonp 跨域與 get/post
我們知道 script,link, img 等等標(biāo)簽引入外部資源,都是 get 請(qǐng)求的,那么就決定了 jsonp 一定是 get 的,那么為什么我們上面的代碼中使用的 post 請(qǐng)求也成功了呢?這是因?yàn)楫?dāng)我們指定dataType:'jsonp',不論你指定:type:"post" 或者type:"get",其實(shí)質(zhì)上進(jìn)行的都是 get 請(qǐng)求!?。膬蓚€(gè)方面可以證明這一點(diǎn):
1)如果我們將JsonServlet中的 doGet()方法注釋掉,那么上面的跨域訪問(wèn)就不能進(jìn)行,或者在 doPost() 和 doGet() 方法中進(jìn)行調(diào)試,都可以證明這一點(diǎn);
2)我們看下firebug中的“網(wǎng)絡(luò)”選項(xiàng)卡:
我們看到,即使我們指定 type:"post",當(dāng)dataType:"jsonp" 時(shí),進(jìn)行的也是 GET請(qǐng)求,而不是post請(qǐng)求,也就是說(shuō)jsonp時(shí),type參數(shù)始終是"get",而不論我們指定他的值是什么,jquery在里面將它設(shè)定為了get. 我們甚至可以將 type 參數(shù)注釋掉,都可以跨域成功:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$(function(){
$("a").on("click", function(){
$.ajax({
//type:"post",
url:"http://localhost:8080/html5/JsonServlet",
dataType:'jsonp',
jsonp:'mycallback',
jsonpCallback:'callbackFun',
success:function(data) {
console.log(2222);
console.log(data.age);
}
});
})
});
所以jsonp跨域只能是get,jquery在封裝jsonp跨域時(shí),不論我們指定的是get還是post,他統(tǒng)一換成了get請(qǐng)求,估計(jì)這樣可以減少錯(cuò)誤吧。其對(duì)應(yīng)的query源碼如下所示:
// Handle cache's special case and globaljQuery.ajaxPrefilter( "script", function( s ) { if ( s.cache === undefined ) { s.cache = false; } if ( s.crossDomain ) { s.type = "GET"; s.global = false; }});
if( s.crossDomain){ s.type = "GET"; ...} 這里就是真相?。。。。。。。≡赼jax的過(guò)濾函數(shù)中,只要是跨域,jquery就將其type設(shè)置成"GET",真是那句話:在源碼面前,一切了無(wú)秘密!jquery源碼我自己很多地方讀不懂,但是并不妨礙我們?nèi)プx,去探索!
4.除了jsonp跨域方法之外的其他跨域方法
其實(shí)除了jsonp跨域之外,還有其他方法繞過(guò)同源策略,
1)因?yàn)橥床呗允轻槍?duì)客戶端的,在服務(wù)器端沒(méi)有什么同源策略,是可以隨便訪問(wèn)的,所以我們可以通過(guò)下面的方法繞過(guò)客戶端的同源策略的限制:客戶端先訪問(wèn) 同源的服務(wù)端代碼,該同源的服務(wù)端代碼,使用httpclient等方法,再去訪問(wèn)不同源的 服務(wù)端代碼,然后將結(jié)果返回給客戶端,這樣就間接實(shí)現(xiàn)了跨域。相關(guān)例子,參見(jiàn)博文:http://www.cnblogs.com/digdeep/p/4198643.html
2)在服務(wù)端開(kāi)啟cors也可以支持瀏覽器的跨域訪問(wèn)。cors即:Cross-Origin Resource Sharing 跨域資源共享。jsonp和cors的區(qū)別是jsonp幾乎所有瀏覽器都支持,但是只能是get,而cors有些老瀏覽器不支持,但是get/post都支持,cors的支持情況,可以參見(jiàn)下圖(來(lái)自:http://caniuse.com/#search=cors)
cors實(shí)例:
項(xiàng)目html5中的Cors servlet:
public class Cors extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "Content-Type"); response.getWriter().write("cors get"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "Content-Type"); response.getWriter().write("cors post"); }}
在html4項(xiàng)目中訪問(wèn)他:
<!doctype html><html><head> <meta charset="utf-8"> <meta name="keywords" content="jsonp"> <meta name="description" content="jsonp"> <title>cors</title> <style type="text/css"> *{margin:0;padding:0;} div{width:600px;height:100px;margin:20px auto;} </style></head><body> <div> <a href="javascript:;">cors測(cè)試</a> </div> <script type="text/javascript" src="js/jquery-1.11.1.js"></script><script type="text/javascript">$(function(){ $("a").on("click", function(){ $.ajax({ type:"post", url:"http://localhost:8080/html5/cors", success:function(data) { console.log(data); alert(data); } }); })}); </script></body></html>
訪問(wèn)結(jié)果如下:
5. 參數(shù)jsonp 和 jsonpCallback
jsonp指定使用哪個(gè)名字將回調(diào)函數(shù)傳給服務(wù)端,也就是在服務(wù)端通過(guò) request.getParameter(""); 的那個(gè)名字,而jsonpCallback就是request.getParamete("")取得的值,也就是回調(diào)函數(shù)的名稱。其實(shí)這兩個(gè)參數(shù)都可以不指定,只要我們是通過(guò) success : 來(lái)指定回調(diào)函數(shù)的情況下,就可以省略這兩個(gè)參數(shù),jsnop如果不知道,默認(rèn)是 "callback",jsnpCallback不指定,是jquery自動(dòng)生成的一個(gè)函數(shù)名稱,其對(duì)應(yīng)源碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
var oldCallbacks = [],
rjsonp = /(=)\?(?=&|$)|\?\?/;
// Default jsonp settings
jQuery.ajaxSetup({
jsonp: "callback",
jsonpCallback: function() {
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
this[ callback ] = true;
return callback;
}
});
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
JSON for jQuery
說(shuō)說(shuō)JSON和JSONP,也許你會(huì)豁然開(kāi)朗
jQuery jsonp跨域請(qǐng)求詳解
關(guān)于jquery跨域請(qǐng)求方法
解決同一頁(yè)面jQuery多個(gè)版本或和其他js庫(kù)沖突方法
MVVM 和 VUE - 水墨墨心 - 博客園
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服