現在咱們一起來討論瀏覽器跨域請求數據的相關問題。說這樣可能不是很標準,因為拒絕跨域請求數據并不是瀏覽器所獨有的,之所以會出現跨域請求不了數據,是因為瀏覽器基本都實現了一個叫"同源策略"的安全規(guī)范。該規(guī)范具體是什么呢?我們在mdn上找到了一份資料,地址如下:
總的來說,當a網址和b網址在 協(xié)議 、 端口 、 域名 方面存在不同時,瀏覽器就會啟動同源策略,拒絕a、b服務器之間進行數據請求。
說了同源策略,紙上得來終覺淺,絕知此事要躬行,到底同源策略是怎么體現的呢?下面我將結合代碼一步一步進行演示。
1、a服務器請求不了b服務器的情況
既然是跨域,我就假設我有兩個域名,分別是 a 和 localhost , a 表示小編在阿里云上主機域名, localhost 顧名思義就是小編的開發(fā)機器了。我們想象這樣一個場景,在 localhost 上部署一個 index.html 文件,在 a 服務器上部署一個簡單的 spring-boot 后臺服務,并提供一個簡單的接口暴露給 index.html 文件調用,最后瀏覽器請求 localhost 的 index.html 文件,看瀏覽器提示什么?
index.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
|
<!doctype html> <html> <head> <title>測試跨域訪問</title> <meta charset= "utf-8" /> </head> <body> <script src= "https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js" ></script> <script type= "text/javascript" > $(document).ready(function() { $.ajax({ type : "get" , async : true , url : "http://a/hello/map/getuser.json" ,// 請求a服務器上的接口 type : "json" , success : function(data) { // 打印返回的數據 console.log( "success,and return data is " + data); } }); }); </script> <h2>hello world</h2> </body> </html> |
瀏覽器上請求 index.html 文件,顯示如下:
可以發(fā)現,請求被瀏覽器給拒絕了,提示我們不允許跨域請求數據,很難受,怎么解決呢?
2、使用 jsonp 解決跨域請求
首先講下原理,jsonp解決跨域問題主要利用了 <script> 標簽的可跨域性,也就是 src 屬性中的鏈接地址可以跨域訪問的特性,因為我們經常將 src 屬性值設置為cdn的地址,已加載相關的js庫。
index.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
|
<!doctype html> <html> <head> <title>測試跨域訪問</title> <meta charset= "utf-8" /> </head> <body> <script src= "https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js" ></script> <script type= "text/javascript" > $(document).ready(function() { $.ajax({ type : "get" , async : true , jsonp : "callbackname" , // 后端接口參數名 jsonpcallback : "callbackfunction" , // 回調函數名 url : "http://a/hello/map/getuser.json" , datatype : "jsonp" , // 數據格式為 jsonp success : function(data) { console.log( "success" ); } }); }); </script> <script type= "text/javascript" > var callbackfunction = function(data) { alert( '接口返回的數據是:' + json.stringify(data)); }; </script> </body> </html> |
a 服務器上的接口代碼為:
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
45
|
/** * * the class jsonbackcontroller. * * description:該控制器返回一串簡單的json數據,json數據由一個簡單的user對象組成 * * @author: huangjiawei * @since: 2018年6月12日 * @version: $revision$ $date$ $lastchangedby$ * */ @restcontroller @requestmapping (value = "/map" ) public class jsonbackcontroller { private static final logger logger = loggerfactory.getlogger(jsonbackcontroller. class ); /** * 解決跨域請求數據 * @param response * @param callbackname 前端回調函數名 * @return */ @requestmapping (value = "getuser.json" ) public void getuser(httpservletresponse response, @requestparam string callbackname) { user user = new user( "huangjiawei" , 22 ); response.setcontenttype( "text/javascript" ); writer writer = null ; try { writer = response.getwriter(); writer.write(callbackname + "(" ); writer.write(user.tostring()); writer.write( ");" ); } catch (ioexception e) { logger.error( "jsonp響應寫入失敗! 數據:" + user.tostring(), e); } finally { if (writer != null ) { try { writer.close(); } catch (ioexception e) { logger.error( "輸出流關閉異常!" , e); } writer = null ; } } } } |
后端傳入一個參數 callbackname 回調函數名,然后返回一段js代碼給前端,js代碼格式如下:
callbackname + ( data ) + ;
瀏覽器請求 localhost 服務器上的 index.html 文件,結果如下:
上面這種方式是通過 jquery + jsonp 解決跨域問題的,剛剛不是說可以用 <script> 標簽的 src 屬性嗎?四的。
localhost 服務器上的 index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!doctype html> <html> <head> <title>測試跨域訪問</title> <meta charset= "utf-8" /> </head> <body> <script src= "https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js" ></script> <script type= "text/javascript" > var callbackfunction = function(data) { alert( '接口返回的數據是:' + json.stringify(data)); }; </script> <script type= "text/javascript" src= "http://a/hello/map/getuser.json?callbackname=callbackfunction" ></script> </body> </html> |
瀏覽器顯示效果和上面一致。但此處需要注意的是, src 表示引入一個js文件,由于是直接調用接口,而接口返回的數據又剛好是一段js代碼,故能被執(zhí)行。另外,第二個 <script> 標簽順序不能顛倒,不然會出現 callbackfunction 函數找不到的情況。
工程代碼地址 : https://github.com/smallercoder/jsonpdemo
最后總結下,解決跨域的方案有很多種,jsonp只是其中一種,具體情況需要具體分析。希望此文對你有幫助,謝謝閱讀,歡迎github給顆 start ,么么噠!也希望大家多多支持服務器之家。
原文鏈接:https://juejin.im/post/5b1f8bc05188257d7541c2ce