springboot+jsonp解決前端跨域問(wèn)題小結(jié)
現(xiàn)在咱們一起來(lái)討論瀏覽器跨域請(qǐng)求數(shù)據(jù)的相關(guān)問(wèn)題。說(shuō)這樣可能不是很標(biāo)準(zhǔn),因?yàn)榫芙^跨域請(qǐng)求數(shù)據(jù)并不是瀏覽器所獨(dú)有的,之所以會(huì)出現(xiàn)跨域請(qǐng)求不了數(shù)據(jù),是因?yàn)闉g覽器基本都實(shí)現(xiàn)了一個(gè)叫"同源策略"的安全規(guī)范。該規(guī)范具體是什么呢?我們?cè)贛DN上找到了一份資料,地址如下:
總的來(lái)說(shuō),當(dāng)A網(wǎng)址和B網(wǎng)址在 協(xié)議 、 端口 、 域名 方面存在不同時(shí),瀏覽器就會(huì)啟動(dòng)同源策略,拒絕A、B服務(wù)器之間進(jìn)行數(shù)據(jù)請(qǐng)求。
說(shuō)了同源策略,紙上得來(lái)終覺(jué)淺,絕知此事要躬行,到底同源策略是怎么體現(xiàn)的呢?下面我將結(jié)合代碼一步一步進(jìn)行演示。
1、A服務(wù)器請(qǐng)求不了B服務(wù)器的情況
既然是跨域,我就假設(shè)我有兩個(gè)域名,分別是 A 和 localhost , A 表示小編在阿里云上主機(jī)域名, localhost 顧名思義就是小編的開(kāi)發(fā)機(jī)器了。我們想象這樣一個(gè)場(chǎng)景,在 localhost 上部署一個(gè) index.html 文件,在 A 服務(wù)器上部署一個(gè)簡(jiǎn)單的 spring-boot 后臺(tái)服務(wù),并提供一個(gè)簡(jiǎn)單的接口暴露給 index.html 文件調(diào)用,最后瀏覽器請(qǐng)求 localhost 的 index.html 文件,看瀏覽器提示什么?
index.html
<!DOCTYPE html> <html> <head> <title>測(cè)試跨域訪問(wèn)</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",// 請(qǐng)求A服務(wù)器上的接口 type : "json", success : function(data) { // 打印返回的數(shù)據(jù) console.log("success,and return data is " + data); } }); }); </script> <h2>hello world</h2> </body> </html>
瀏覽器上請(qǐng)求 index.html 文件,顯示如下:
可以發(fā)現(xiàn),請(qǐng)求被瀏覽器給拒絕了,提示我們不允許跨域請(qǐng)求數(shù)據(jù),很難受,怎么解決呢?
2、使用 jsonp 解決跨域請(qǐng)求
首先講下原理,jsonp解決跨域問(wèn)題主要利用了 <script> 標(biāo)簽的可跨域性,也就是 src 屬性中的鏈接地址可以跨域訪問(wèn)的特性,因?yàn)槲覀兘?jīng)常將 src 屬性值設(shè)置為cdn的地址,已加載相關(guān)的js庫(kù)。
index.html
<!DOCTYPE html> <html> <head> <title>測(cè)試跨域訪問(wèn)</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",// 后端接口參數(shù)名 jsonpCallback : "callbackFunction", // 回調(diào)函數(shù)名 url : "http://A/hello/map/getUser.json", dataType : "jsonp", // 數(shù)據(jù)格式為 jsonp success : function(data) { console.log("success"); } }); }); </script> <script type="text/javascript"> var callbackFunction = function(data) { alert('接口返回的數(shù)據(jù)是:' + JSON.stringify(data)); }; </script> </body> </html>
A 服務(wù)器上的接口代碼為:
/** * * The class JsonBackController. * * Description:該控制器返回一串簡(jiǎn)單的json數(shù)據(jù),json數(shù)據(jù)由一個(gè)簡(jiǎn)單的User對(duì)象組成 * * @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); /** * 解決跨域請(qǐng)求數(shù)據(jù) * @param response * @param callbackName 前端回調(diào)函數(shù)名 * @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響應(yīng)寫(xiě)入失??! 數(shù)據(jù):" + user.toString(), e); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { logger.error("輸出流關(guān)閉異常!", e); } writer = null; } } } }
后端傳入一個(gè)參數(shù) callbackName 回調(diào)函數(shù)名,然后返回一段js代碼給前端,js代碼格式如下:
callbackName + ( data ) + ;
瀏覽器請(qǐng)求 localhost 服務(wù)器上的 index.html 文件,結(jié)果如下:
上面這種方式是通過(guò) jquery + jsonp 解決跨域問(wèn)題的,剛剛不是說(shuō)可以用 <script> 標(biāo)簽的 src 屬性嗎?四的。
localhost 服務(wù)器上的 index.html
<!DOCTYPE html> <html> <head> <title>測(cè)試跨域訪問(wèn)</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('接口返回的數(shù)據(jù)是:' + JSON.stringify(data)); }; </script> <script type="text/javascript" src="http://A/hello/map/getUser.json?callbackName=callbackFunction"></script> </body> </html>
瀏覽器顯示效果和上面一致。但此處需要注意的是, src 表示引入一個(gè)js文件,由于是直接調(diào)用接口,而接口返回的數(shù)據(jù)又剛好是一段js代碼,故能被執(zhí)行。另外,第二個(gè) <script> 標(biāo)簽順序不能顛倒,不然會(huì)出現(xiàn) callbackFunction 函數(shù)找不到的情況。
工程代碼地址 : https://github.com/SmallerCoder/jsonpDemo
最后總結(jié)下,解決跨域的方案有很多種,jsonp只是其中一種,具體情況需要具體分析。希望此文對(duì)你有幫助,謝謝閱讀,歡迎github給顆 start ,么么噠!也希望大家多多支持腳本之家。
相關(guān)文章
如何基于springboot-admin實(shí)現(xiàn)后臺(tái)監(jiān)控
這篇文章主要介紹了如何基于springboot-admin實(shí)現(xiàn)后臺(tái)監(jiān)控,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04Mybatis?Web中的數(shù)據(jù)庫(kù)操作方法舉例詳解
Mybatis是一款優(yōu)秀的持久化框架,用于簡(jiǎn)化JDBC的開(kāi)發(fā),下面這篇文章主要給大家介紹了關(guān)于Mybatis?Web中數(shù)據(jù)庫(kù)操作方法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09Java SpringBoot微服務(wù)框架驗(yàn)證碼報(bào)錯(cuò)問(wèn)題解決方案
這篇文章主要介紹了Java SpringBoot微服務(wù)框架驗(yàn)證碼報(bào)錯(cuò)問(wèn)題解決方案,包括dockerfile容器操作和完整dockerfile,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-08-08java基礎(chǔ)之 “==”與“equals”區(qū)別詳解
這篇文章主要介紹了java基礎(chǔ)之 “==”與“equals”區(qū)別詳解,需要的朋友可以參考下2020-02-02swagger配置正式環(huán)境中不可訪問(wèn)的問(wèn)題
這篇文章主要介紹了swagger配置正式環(huán)境中不可訪問(wèn)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06SpringBoot操作Mongodb的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot操作Mongodb的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06