技術(shù)愛(ài)好者
https://blog.csdn.net/m_jack/article/details/80497617
一、什么是跨域訪問(wèn)
舉個(gè)栗子:在A網(wǎng)站中,我們希望使用Ajax來(lái)獲得B網(wǎng)站中的特定內(nèi)容。如果A網(wǎng)站與B網(wǎng)站不在同一個(gè)域中,那么就出現(xiàn)了跨域訪問(wèn)問(wèn)題。你可以理解為兩個(gè)域名之間不能跨過(guò)域名來(lái)發(fā)送請(qǐng)求或者請(qǐng)求數(shù)據(jù),否則就是不安全的??缬蛟L問(wèn)違反了同源策略,同源策略的詳細(xì)信息可以點(diǎn)擊如下鏈接:Same-origin_policy;
總而言之,同源策略規(guī)定,瀏覽器的ajax只能訪問(wèn)跟它的HTML頁(yè)面同源(相同域名或IP)的資源。
二、什么是JSONP
JSONP(JSON with Padding)是JSON的一種“使用模式”,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問(wèn)的問(wèn)題。
由于同源策略,一般來(lái)說(shuō)位于 server1.example.com 的網(wǎng)頁(yè)無(wú)法與不是 server1.example.com的服務(wù)器溝通,而 HTML 的元素是一個(gè)例外。利用元素的這個(gè)開(kāi)放策略,網(wǎng)頁(yè)可以得到從其他來(lái)源動(dòng)態(tài)產(chǎn)生的JSON 資料,而這種使用模式就是所謂的 JSONP。用 JSONP 抓到的資料并不是JSON,而是任意的JavaScript,用 JavaScript 直譯器執(zhí)行而不是用JSON 解析器解析。更具體的原理需要更多篇幅的講解,小伙伴可以自行去百度。
三、JSONP的使用
前端的使用示例
JQuery Ajax對(duì)JSONP進(jìn)行了很好的封裝,我們使用起來(lái)很方便。前端示例:
? ? $.ajax({
type:"GET",
url:"http://www.deardull.com:9090/getMySeat",//訪問(wèn)的鏈接
dataType:"jsonp",//數(shù)據(jù)格式設(shè)置為jsonp
jsonp:"callback",//Jquery生成驗(yàn)證參數(shù)的名稱
success:function(data){//成功的回調(diào)函數(shù)
? ? ? ? ? ? ? ? alert(data);
? ? ? ? ? ? },
error:function (e) {
alert("error");
? ? ? ? ? ? }
? ? ? ? });
需要注意的地方是:
dataType,該參數(shù)必須要設(shè)置成jsonp
jsonp,該參數(shù)的值需要與服務(wù)器端約定,詳細(xì)情況下面介紹。(約定俗成的默認(rèn)值為callback)
后端的配合示例
JQuery Ajax Jsonp原理
后端要配合使用jsonp,那么首先得了解Jquery Ajax jsonp的一個(gè)特點(diǎn):
Jquery在發(fā)送一個(gè)Ajax jsonp請(qǐng)求時(shí),會(huì)在訪問(wèn)鏈接的后面自動(dòng)加上一個(gè)驗(yàn)證參數(shù),這個(gè)參數(shù)是Jquery隨機(jī)生成的,例如鏈接
http://www.deardull.com:9090/getMySeat?callback=jQuery31106628680598769732_1512186387045&_=1512186387046
中,參數(shù)callback=jQuery31106628680598769732_1512186387045&_=1512186387046就是jquery自動(dòng)添加的。
添加這個(gè)參數(shù)的目的是唯一標(biāo)識(shí)這次請(qǐng)求。當(dāng)服務(wù)器端接收到該請(qǐng)求時(shí),需要將該參數(shù)的值與實(shí)際要返回的json值進(jìn)行構(gòu)造(如何構(gòu)造下面講解),并且返回,而前端會(huì)驗(yàn)證這個(gè)參數(shù),如果是它之前發(fā)出的參數(shù),那么就會(huì)接收并解析數(shù)據(jù),如果不是這個(gè)參數(shù),那么就拒絕接受。
需要特別注意的是這個(gè)驗(yàn)證參數(shù)的名字(我在這個(gè)坑上浪費(fèi)了2小時(shí)),這個(gè)名字來(lái)源于前端的jsonp參數(shù)的值。如果把前端jsonp參數(shù)的值改為“aaa”,那么相應(yīng)的參數(shù)就應(yīng)該是
aaa=jQuery31106628680598769732_1512186387045&_=1512186387046
后端接收與處理
知道了Jquery Ajax Jsonp的原理,也知道了需要接受的參數(shù),我們就可以來(lái)編寫服務(wù)器端程序了。
為了配合json,服務(wù)器端需要做的事情可以概括為兩步:
第一步、接收驗(yàn)證參數(shù)
根據(jù)與前端Ajax約定的jsonp參數(shù)名來(lái)接收驗(yàn)證參數(shù),示例如下(使用SpringMVC,其他語(yǔ)言及框架原理類似)
? ? @ResponseBody
@RequestMapping("/getJsonp")
publicString getMySeatSuccess(@RequestParam("callback")String callback){
第二步、構(gòu)造參數(shù)并返回
將接收的的驗(yàn)證參數(shù)callback與實(shí)際要返回的json數(shù)據(jù)按“callback(json)”的方式構(gòu)造:
? ? ?@ResponseBody
@RequestMapping("/getMySeat")
publicString getMySeatSuccess(@RequestParam("callback")String callback){
Gson gson=new Gson();//google的一個(gè)json工具庫(kù)
Map map=new HashMap<>();
map.put("seat","1_2_06_12");
return callback+"("+gson.toJson(map)+")";//構(gòu)造返回值
? ? }
四、總結(jié)
最終,前后端的相應(yīng)代碼應(yīng)該是這樣的:
前端
? ? $.ajax({
type:"GET",
url:"http://www.deardull.com:9090/getMySeat",//訪問(wèn)的鏈接
dataType:"jsonp",//數(shù)據(jù)格式設(shè)置為jsonp
jsonp:"callback",//Jquery生成驗(yàn)證參數(shù)的名稱
success:function(data){//成功的回調(diào)函數(shù)
? ? ? ? ? ? ? ? alert(data);
? ? ? ? ? ? },
error:function (e) {
alert("error");
? ? ? ? ? ? }
? ? ? ? });
后端
? ? @ResponseBody
@RequestMapping("/getMySeat")
publicString getMySeatSuccess(@RequestParam("callback")String callback){
Gson gson=new Gson();
Map map=new HashMap<>();
map.put("seat","1_2_06_12");
? ? ? ? logger.info(callback);
return callback+"("+gson.toJson(map)+")";
? ? }
需要注意的是:
前端注意與后端溝通約定jsonp的值,通常默認(rèn)都是用callback。
后端根據(jù)jsonp參數(shù)名獲取到參數(shù)后要與本來(lái)要返回的json數(shù)據(jù)按“callback(json)”的方式構(gòu)造。
如果要測(cè)試的話記得在跨域環(huán)境(兩臺(tái)機(jī)器)下進(jìn)行。
完整的示例就是上面兩段代碼,這里就不提供Github連接了。上面的示例親測(cè)有效,如果有遇到問(wèn)題的,歡迎留言提問(wèn)。
原文:https://blog.csdn.net/zhoucheng05_13/article/details/78694766?utm_source=copy?
什么是跨域?
跨域,指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對(duì)JavaScript施加的安全限制。
所謂同源是指,域名,協(xié)議,端口均相同,不明白沒(méi)關(guān)系,舉個(gè)栗子:
http://www.123.com/index.html 調(diào)用 http://www.123.com/server.PHP(非跨域)
http://www.123.com/index.html 調(diào)用 http://www.456.com/server.php(主域名不同:123/456,跨域)
http://abc.123.com/index.html 調(diào)用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 調(diào)用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.123.com/index.html 調(diào)用 https://www.123.com/server.php (協(xié)議不同:http/https,跨域)
請(qǐng)注意:localhost和127.0.0.1雖然都指向本機(jī),但也屬于跨域。
瀏覽器執(zhí)行javascript腳本時(shí),會(huì)檢查這個(gè)腳本屬于哪個(gè)頁(yè)面,如果不是同源頁(yè)面,就不會(huì)被執(zhí)行。
你可以理解為兩個(gè)域名之間不能跨過(guò)域名來(lái)發(fā)送請(qǐng)求或者請(qǐng)求數(shù)據(jù),否則就是不安全的,這種不安全也就是CSRF(Cross-site
request forgery),中文名稱:跨站請(qǐng)求偽造,也被稱為:one click attack/session
riding,縮寫為:CSRF/XSRF。
一張圖解釋什么是CSRF

首先我們來(lái)想一想
? ? ? ? ? ? ? 為什么會(huì)有跨域這個(gè)名詞的出現(xiàn)呢?
? ? ? ? ? ? ? 跨域又是什么呢?為何要跨域?
? ? ? ? ? ? ? 瀏覽器的同源策略又是什么?怎么解決?
? ? ? ? ? ? ? jsonp又是什么?
? ? ? ? ? ? ? 跨域的原理又是什么呢?
名詞解釋:
跨域:
瀏覽器對(duì)于javascript的同源策略的限制,例如a.cn下面的js不能調(diào)用b.cn中的js,對(duì)象或數(shù)據(jù)(因?yàn)閍.cn和b.cn是不同域),所以跨域就出現(xiàn)了.
上面提到的,同域的概念又是什么呢??? 簡(jiǎn)單的解釋就是相同域名,端口相同,協(xié)議相同
同源策略:
請(qǐng)求的url地址,必須與瀏覽器上的url地址處于同域上,也就是域名,端口,協(xié)議相同.
比如:我在本地上的域名是study.cn,請(qǐng)求另外一個(gè)域名一段數(shù)據(jù)

這個(gè)時(shí)候在瀏覽器上會(huì)報(bào)錯(cuò):

這個(gè)就是同源策略的保護(hù),如果瀏覽器對(duì)javascript沒(méi)有同源策略的保護(hù),那么一些重要的機(jī)密網(wǎng)站將會(huì)很危險(xiǎn)~
study.cn/json/jsonp/jsonp.html
?請(qǐng)求地址?形式?結(jié)果
?http://study.cn/test/a.html同一域名,不同文件夾?成功
?http://study.cn/json/jsonp/jsonp.html同一域名,統(tǒng)一文件夾?成功
?http://a.study.cn/json/jsonp/jsonp.html不同域名,文件路徑相同?失敗
?http://study.cn:8080/json/jsonp/jsonp.html?同一域名,不同端口?失敗
?https://study.cn/json/jsonp/jsonp.html?同一域名,不同協(xié)議 ?失敗
jsonp:
jsonp全稱是JSON with Padding,是為了解決跨域請(qǐng)求資源而產(chǎn)生的解決方案,是一種依靠開(kāi)發(fā)人員創(chuàng)造出的一種非官方跨域數(shù)據(jù)交互協(xié)議。
一個(gè)是描述信息的格式,一個(gè)是信息傳遞雙方約定的方法。
jsonp的產(chǎn)生:
1.AJAX直接請(qǐng)求普通文件存在跨域無(wú)權(quán)限訪問(wèn)的問(wèn)題,不管是靜態(tài)頁(yè)面也好.
2.不過(guò)我們?cè)谡{(diào)用js文件的時(shí)候又不受跨域影響,比如引入jquery框架的,或者是調(diào)用相片的時(shí)候
3.凡是擁有scr這個(gè)屬性的標(biāo)簽都可以跨域例如<script><img><iframe>
4.如果想通過(guò)純web端跨域訪問(wèn)數(shù)據(jù)只有一種可能,那就是把遠(yuǎn)程服務(wù)器上的數(shù)據(jù)裝進(jìn)js格式的文件里.
5.而json又是一個(gè)輕量級(jí)的數(shù)據(jù)格式,還被js原生支持
6.為了便于客戶端使用數(shù)據(jù),逐漸形成了一種非正式傳輸協(xié)議,人們把它稱作JSONP,該協(xié)議的一個(gè)要點(diǎn)就是允許用戶傳遞一個(gè)callback?參數(shù)給服務(wù)端,
demo1:基于script標(biāo)簽實(shí)現(xiàn)跨域
舉個(gè)例子:我在http://study.cn/json/jsonp/jsonp_2.html下請(qǐng)求一個(gè)遠(yuǎn)程的js文件

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>Insert title here</title>
6
7 <script type="text/javascript">
8? ? var message = function(data) {
9? ? ? ? alert(data[1].title);
10? ? };
11 </script>
12
13 <script type="text/javascript" src="http://web.cn/js/message.js"></script>
14 </head>
15 <body>
16 <div id='testdiv'></div>
17 </body>
18 </html>

遠(yuǎn)程的message.js文件是

1 message([
2? ? ? {"id":"1", "title":"天津新聞聯(lián)播,雷人搞笑的男主持人"},
3? ? ? {"id":"2", "title":"樓市告別富得流油 專家:房?jī)r(jià)下跌是大概率事件"},
4? ? ? {"id":"3", "title":"法國(guó)人關(guān)注時(shí)事 八成年輕人每天閱讀新聞"},
5? ? ? {"id":"4", "title":"新聞中的歷史,歷史中的新聞"},
6? ? ? {"id":"5", "title":"東陽(yáng)新聞20140222"},
7? ? ? {"id":"6", "title":"23個(gè)職能部門要增加新聞發(fā)布頻次"},
8? ? ? {"id":"7", "title":"《貴州新聞聯(lián)播》 中國(guó)美麗鄉(xiāng)村"},
9? ? ? {"id":"8", "title":"朝韓離散家屬團(tuán)聚首輪活動(dòng)結(jié)束"},
10? ? ? {"id":"9", "title":"索契冬奧會(huì)一天曝出兩例興奮劑事件"},
11? ? ? {"id":"10", "title":"今天中國(guó)多地仍將出現(xiàn)中度霾"}
12? ]);

這個(gè)時(shí)候我們得到的相應(yīng)頭是:

這樣就實(shí)現(xiàn)跨域成功了,因?yàn)榉?wù)端返回?cái)?shù)據(jù)時(shí)會(huì)將這個(gè)callback參數(shù)(message)作為函數(shù)名來(lái)包裹住JSON數(shù)據(jù),這樣客戶端就可以隨意定制自己的函數(shù)來(lái)自動(dòng)處理返回?cái)?shù)據(jù)了。
demo2:?基于script標(biāo)簽實(shí)現(xiàn)跨域
讓遠(yuǎn)程js知道它應(yīng)該調(diào)用的本地函數(shù)叫什么名字,只要服務(wù)端提供的js腳本是動(dòng)態(tài)生成的就好了,這樣前臺(tái)只需要傳一個(gè)callback參數(shù)過(guò)去告訴服務(wù)端,我需要XXX代碼,于是服務(wù)端就會(huì)得到相應(yīng)了.
例如 在http://study.cn/json/jsonp/jsonp_3.html頁(yè)面請(qǐng)求?http://192.168.31.137/train/test/jsonpthree

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>Insert title here</title>
6
7 <script type="text/javascript">
8? ? var messagetow = function(data){
9? ? ? ? alert(data);
10? ? };
11? ? var url = "http://192.168.31.137/train/test/jsonpthree?callback=messagetow";
12? ? var script = document.createElement('script');
13? ? script.setAttribute('src', url);
14? ? document.getElementsByTagName('head')[0].appendChild(script);
15 </script>
16 </head>
17 <body>
18 </body>
19 </html>

得到的響應(yīng)頭是:

demo3:??基于jquery跨域
那么如何用jquery來(lái)實(shí)現(xiàn)我們的跨域呢???jquery已經(jīng)把跨域封裝到ajax上了,而且封裝得非常的好,使用起來(lái)也特別方便
如果是一般的ajax請(qǐng)求:

1? ? $.ajax({
2? ? ? ? url:'http://192.168.31.137/train/test/testjsonp',
3? ? ? ? type : 'get',
4? ? ? ? dataType : 'text',
5? ? ? ? success:function(data){
6? ? ? ? ? ? alert(data);
7? ? ? ? },
8? ? ? ? error:function(data){
9? ? ? ? ? ? alert(2);
10? ? ? ? }? ? ? ?
11? ? });

那么在瀏覽器中會(huì)報(bào)錯(cuò):

jsonp形式的ajax請(qǐng)求:并且通過(guò)get請(qǐng)求的方式傳入?yún)?shù),注意:跨域請(qǐng)求是只能是get請(qǐng)求不能使用post請(qǐng)求

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>Insert title here</title>
6 <script type="text/javascript" src="./js/jquery.js"></script>
7 <script type="text/javascript">
8 $(document).ready(function(){
9? ? var name = 'chenshishuo';
10? ? var sex = 'man';
11? ? var address = 'shenzhen';
12? ? var looks = 'handsome ';
13? ? ? $.ajax({
14? ? ? ? ? type : 'get',
15? ? ? ? ? url:'http://192.168.31.137/train/test/testjsonp',
16? ? ? ? data : {
17? ? ? ? ? ? name : name,
18? ? ? ? ? ? sex : sex,
19? ? ? ? ? ? address : address,
20? ? ? ? ? ? looks : looks,
21? ? ? ? },
22? ? ? ? cache :false,
23? ? ? ? jsonp: "callback",
24? ? ? ? jsonpCallback:"success",
25? ? ? ? dataType : 'jsonp',
26? ? ? ? success:function(data){
27? ? ? ? ? ? alert(data);
28? ? ? ? },
29? ? ? ? error:function(data){
30? ? ? ? ? ? alert('error');
31? ? ? ? }? ? ? ?
32? ? });
33 });
34 </script>
35 </head>
36 <body>
37 <input id='inputtest' value='546' name='inputtest'>
38 <div id='testdiv'></div>
39 </body>
40 </html>

jsonp 傳遞給請(qǐng)求處理程序或頁(yè)面的,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(默認(rèn)為:callback)
jsonpCallback 自定義的jsonp回調(diào)函數(shù)名稱,默認(rèn)為jQuery自動(dòng)生成的隨機(jī)函數(shù)名
看看請(qǐng)求頭和相應(yīng)頭吧
請(qǐng)求頭:jquery會(huì)自動(dòng)帶入callback參數(shù),當(dāng)服務(wù)端獲取到這個(gè)參數(shù)后,返回回來(lái).(響應(yīng)頭)


現(xiàn)在是不是明白了跨域的基本原理,和基本的使用方法呢??
上面我們說(shuō)到img中的src可以自動(dòng)調(diào)用遠(yuǎn)程圖片的(這個(gè)比較簡(jiǎn)單我在這里就不說(shuō)了)
還有ifram請(qǐng)求:
基于iframe實(shí)現(xiàn)的跨域要求兩個(gè)域具有aa.xx.com,bb.xx.com 這種特點(diǎn),
也就是兩個(gè)頁(yè)面必須屬于一個(gè)基礎(chǔ)域(例如都是xxx.com),使用同一協(xié)議和同一端口,這樣在兩個(gè)頁(yè)面中同時(shí)添加document.domain,就可以實(shí)現(xiàn)父頁(yè)面調(diào)用子頁(yè)面的函數(shù)
要點(diǎn)就是 :通過(guò)修改document.domain來(lái)跨子域
demo4:?通過(guò)iframe來(lái)跨子域
http://a.study.cn/a.html 請(qǐng)求 http://b.study.cn/b.html
在a.html:

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>Insert title here</title>
6? ? ? ? <script type="text/javascript">
7? ? ? ? ? ? document.domain = 'study.cn';
8? ? ? ? ? ? function test() {
9? ? ? ? ? ? ? ? alert(document.getElementById('a').contentWindow);
10? ? ? ? ? ? }
11? ? ? ? </script>
12 </head>
13 <body>
14? ? <iframe id='a' src='http://b.study.cn/b.html' onload='test()'>
15 </body>
16 </html>

?在b.html:

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>Insert title here</title>
6
7 <script type="text/javascript">
8 document.domain = 'study.cn';
9 </script>
10 </head>
11 <body>
12? ? 我是b.study.cn的body
13 </body>
14 </html>

?運(yùn)行效果截圖:

我們就可以通過(guò)js訪問(wèn)到iframe中的各種屬性和對(duì)象了
如果你想在http://a.study.cn/a.html頁(yè)面中通過(guò)ajax直接請(qǐng)求頁(yè)面http://b.study.cn/b.html,即使你設(shè)置了相同的document.domain也還是不行的.
所以修改document.domain的方法只適用于不同子域的框架(父類與子類)間的交互。
如果想通過(guò)使用ajax的方法去與不同子域間的數(shù)據(jù)交互或者是js調(diào)用,只有兩種方法,一種是使用jsonp的方法外,還有一種是使用iframe來(lái)做一個(gè)代理。
原理就是讓這個(gè) iframe載入一個(gè)與你想要通過(guò)ajax獲取數(shù)據(jù)的目標(biāo)頁(yè)面處在相同的域的頁(yè)面,所以這個(gè)iframe中的頁(yè)面是可以正常使用ajax去獲取你要的數(shù)據(jù) 的,
然后就是通過(guò)我們剛剛講得修改document.domain的方法,讓我們能通過(guò)js完全控制這個(gè)iframe,這樣我們就可以讓iframe去發(fā) 送ajax請(qǐng)求,然后收到的數(shù)據(jù)我們也可以獲得了。
上面的所有知識(shí)點(diǎn),應(yīng)該可以解決第一開(kāi)始提出的問(wèn)題了吧.



0
0
? 上一篇:Windows中殺死占用某個(gè)端口的進(jìn)程
? 下一篇:Maven構(gòu)建可執(zhí)行的jar包(包含依賴jar包)
posted @2019-03-06 18:37隱隱真閱讀(17) 評(píng)論(0)編輯收藏
(評(píng)論功能已被禁用)
【推薦】超50萬(wàn)C++/C#源碼: 大型實(shí)時(shí)仿真組態(tài)圖形源碼
【前端】SpreadJS表格控件,可嵌入系統(tǒng)開(kāi)發(fā)的在線Excel
【推薦】碼云企業(yè)版,高效的企業(yè)級(jí)軟件協(xié)作開(kāi)發(fā)管理平臺(tái)
【推薦】程序員問(wèn)答平臺(tái),解決您開(kāi)發(fā)中遇到的技術(shù)難題
相關(guān)博文:
·架構(gòu)師給程序員的一封信【轉(zhuǎn)自MSDN】
·WindowsPhone下拉刷新控件 - PullRefreshListBox(二)
·讓Fckeditor支持中文——解決“Error loading "/fckeditor/fckstyles.xml" ”
·【原】Sql Server性能優(yōu)化——Partition(創(chuàng)建分區(qū))
最新新聞:
·MIT 推出 AI 編程語(yǔ)言 Gen:以自動(dòng)化、靈活性和速度見(jiàn)長(zhǎng)
·華為擬獲甲級(jí)測(cè)繪資質(zhì),入局自動(dòng)駕駛地圖業(yè)務(wù)
·聯(lián)通科普eSIM:如果SIM卡“消失”了...
我的標(biāo)簽
English(48)
js(45)
java(40)
spring boot(29)
angularjs(18)
git(16)
eclipse(16)
jQuery(7)
linux(7)
maven(7)
隨筆分類
文章分類