同源策略&跨域
同源策略
對于同源的定義最欠,MDN給出了這樣的解釋:如果兩個(gè)頁面的協(xié)議欺旧,端口(如果有指定)和主機(jī)都相同,則兩個(gè)頁面具有相同的源懈万。
如何確定兩個(gè)頁面是否同源,只要比較兩個(gè)頁面的協(xié)議靶病、域名和端口即可会通。
假設(shè)有這樣一個(gè)頁面http://zhihu.com/main.html,相對于它給出同源檢測的示例:
URL | 結(jié)果 | 原因 |
---|---|---|
http://zhihu.com/other.html | 成功 | 只有路徑不同 |
http://zhihu.com/a/another.html | 成功 | 只有路徑不同 |
https://zhihu.com/page.js | 失敗 | 不同協(xié)議(https和hhtp) |
http://zhihu.com:81/a.html | 失敗 | 不同端口 ( http:// 80是默認(rèn)的) |
http://news.com/b.html | 失敗 | 不同域名 ( news和zhihu ) |
同源策略是瀏覽器最核心也最基本的安全功能娄周。保證用戶信息的安全涕侈,防止惡意的網(wǎng)站竊取數(shù)據(jù)。限制了從同一個(gè)源加載的文檔或腳本如何與來自另一個(gè)源的資源進(jìn)行交互煤辨。這是一個(gè)用于隔離潛在惡意文件的重要安全機(jī)制裳涛。
協(xié)議、端口众辨、域名只要有一個(gè)不相同调违,就不符合同源策略,就會出現(xiàn)跨域泻轰。最常見的就是AJAX請求數(shù)據(jù)技肩。
跨域的解決辦法
一、JSONP
JSONP是如何產(chǎn)生的呢浮声?
1.我們都知道使用AJAX直接請求普通文件存在跨域無權(quán)限訪問的問題虚婿,甭管你是什么,只要你是跨域請求泳挥,一律不準(zhǔn)不可以的然痊;
2.但是我們知道HTML中的
<script><img><iframe>
等標(biāo)簽不受同源策略的影響,擁有跨域的能力屉符。那我們是否能利用這個(gè)特性從其他域下獲取數(shù)據(jù)呢3.我們得出結(jié)論剧浸,要想在web端就跨域訪問其他域的數(shù)據(jù)就有一個(gè)辦法,那就是把數(shù)據(jù)裝進(jìn) JS 格式的文件里矗钟,這樣客戶端就能夠調(diào)用了唆香。
4.但是獲取的數(shù)據(jù)是做為 JS 來執(zhí)行。于是就有一個(gè)問題吨艇,數(shù)據(jù)是 JSON 格式的數(shù)據(jù)躬它,直接作為 JS 運(yùn)行的話我如何去得到這個(gè)數(shù)據(jù)來操作呢?
5.于是我們想到是否可以提前在頁面上聲明一個(gè)函數(shù)东涡,通過接口傳參的方式發(fā)送給后臺冯吓,在經(jīng)過后臺處理發(fā)送給前端(所以JSONP 需要對應(yīng)接口的后端的配合才能實(shí)現(xiàn)倘待。)
示例:
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
這個(gè)請求到達(dá)后端后,后端會去解析callback這個(gè)參數(shù)獲取到字符串showData组贺,在發(fā)送數(shù)據(jù)做如下處理:
之前后端返回?cái)?shù)據(jù): {"city": "hangzhou", "weather": "晴天"} 現(xiàn)在后端返回?cái)?shù)據(jù): showData({"city": "hangzhou", "weather": "晴天"}) 前端script標(biāo)簽在加載數(shù)據(jù)后會把 「showData({“city”: “hangzhou”, “weather”: “晴天”})」做為 js 來執(zhí)行凸舵,這實(shí)際上就是調(diào)用showData這個(gè)函數(shù),同時(shí)參數(shù)是 {“city”: “hangzhou”, “weather”: “晴天”}失尖。 用戶只需要在加載提前在頁面定義好showData這個(gè)全局函數(shù)啊奄,在函數(shù)內(nèi)部處理參數(shù)即可。
<script>
function showData(ret){
console.log(ret);
}
</script>
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
JSONP是通過 script 標(biāo)簽加載數(shù)據(jù)的方式去獲取數(shù)據(jù)當(dāng)做 JS 代碼來執(zhí)行 提前在頁面上聲明一個(gè)函數(shù)雹仿,函數(shù)名通過接口傳參的方式傳給后臺,后臺解析到函數(shù)名后在原始數(shù)據(jù)上「包裹」這個(gè)函數(shù)名整以,發(fā)送給前端胧辽。換句話說,JSONP 需要對應(yīng)接口的后端的配合才能實(shí)現(xiàn)公黑。
具體實(shí)現(xiàn)
server.js代碼
index.html代碼
打開Git Bash邑商,進(jìn)入server.js所在文件夾,輸入 node server.js 凡蚜,瀏覽器打開 http://localhost:8080/index.html
于是我們得出JSONP的原理:
- JSONP本質(zhì)上是利用
<script><img><iframe>
等標(biāo)簽不受同源策略限制人断,可以從不同域加載并執(zhí)行資源的特性,來實(shí)現(xiàn)數(shù)據(jù)跨域傳輸朝蜘。 - JSONP由兩部分組成:回調(diào)函數(shù)和數(shù)據(jù)恶迈。回調(diào)函數(shù)是當(dāng)響應(yīng)到來時(shí)應(yīng)該在頁面中調(diào)用的函數(shù)谱醇,而數(shù)據(jù)就是傳入回調(diào)函數(shù)中的JSON數(shù)據(jù)暇仲。
- JSONP的想法就是,與服務(wù)端約定好一個(gè)回調(diào)函數(shù)名副渴,服務(wù)端接收到請求后奈附,將返回一段 JS代碼,在這段JS代碼中調(diào)用了約定好的回調(diào)函數(shù)煮剧,并且將數(shù)據(jù)作為參數(shù)進(jìn)行傳遞斥滤。當(dāng)網(wǎng)頁接收到這段 Javascript 代碼后,就會執(zhí)行這個(gè)回調(diào)函數(shù)勉盅,這時(shí)數(shù)據(jù)已經(jīng)成功傳輸?shù)娇蛻舳肆恕?/li>