新聞中心
25.1 同源策略
25.1.1 同源
跨域本質(zhì)其實(shí)就是指兩個(gè)地址不同源,不同源的反面不就是同源,同源指的是:如果兩個(gè)URL的協(xié)議、域名和端口號都相同,則就是兩個(gè)同源的URL。

10年積累的成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有鐵東免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
- // 非同源:協(xié)議不同
- http://www.baidu.com
- https://www.baidu.com
- // 同源:協(xié)議、域名、端口號都相同
- http://www.baidu.com
- http://www.baidu.com?query=1
25.1.2 同源策略
同源策略是一個(gè)重要的安全策略,它用于限制一個(gè)origin的文檔或者它加載的加載的腳本如何能與另一個(gè)源的資源進(jìn)行交互。其主要是為了保護(hù)用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù),是瀏覽器在Web頁面層面做的安全保護(hù)。
25.1.3 同源策略的表現(xiàn)
既然同源策略是瀏覽器在Web頁面層面做的保護(hù),那么該層面哪些位置需要進(jìn)行保護(hù)呢?總結(jié)下來主要包含三個(gè)層面:DOM層面、數(shù)據(jù)層面、網(wǎng)絡(luò)層面。
DOM層面
同源策略限制了來自不同源的JavaScript腳本對當(dāng)前DOM對象讀和寫的操作。
數(shù)據(jù)層面
同源策略限制了不同源的站點(diǎn)讀取當(dāng)前站點(diǎn)的Cookie、IndexedDB、localStorage等數(shù)據(jù)。
網(wǎng)絡(luò)層面
同源策略限制了通過XMHttpRequest等方式將站點(diǎn)的數(shù)據(jù)發(fā)送給不同源的站點(diǎn)。
25.2 跨域分類
同源策略保證了瀏覽器的安全,但是如果將這三個(gè)層面限制的死死的,則會(huì)讓程序員的開發(fā)工作舉步維艱,所以瀏覽器需要在最嚴(yán)格的同源策略限制下做一些讓步,這些讓步更多了是在安全性與便捷性的權(quán)衡。其實(shí)跨域的方式就可以認(rèn)為是瀏覽器出讓了一些安全性或在遵守瀏覽器同源策略前提下所采取的一種折中手段。
25.2.1 DOM層面和數(shù)據(jù)層面分類
根據(jù)同源策略,如果兩個(gè)頁面不同源,無法互相操作DOM、訪問數(shù)據(jù),但是兩個(gè)不同源頁面之間進(jìn)行通信是比較常見的情形,典型的例子就是iframe窗口與父窗口之間的通信。隨著歷史的車輪,實(shí)現(xiàn)DOM層面間通信的方式有多種,如下所示:
片段標(biāo)識符
片段標(biāo)識符其核心原理就是通過監(jiān)聽url中hash的改變來實(shí)現(xiàn)數(shù)據(jù)的傳遞,想法真的很巧妙。
- // 父頁面parentHtml.html
- 我是父頁面
- window.onhashchange = function() {
- console.log(decodeURIComponent(window.location.hash));
- };
- document.getElementById('btn').addEventListener('click', () => {
- const iframeDom = document.getElementById('childHtmlId');
- iframeDom.src += '#父傳給子';
- });
- // 子頁面childHtml.html
- 我是子頁面
- window.onhashchange = function() {
- console.log(decodeURIComponent(window.location.hash));
- };
- document.getElementById('btn').addEventListener('click', () => {
- parent.location.href += '#子傳給父';
- });
window.name
瀏覽器窗口有window.name屬性,這個(gè)屬性的最大特點(diǎn)是,無論是否同源,只要在同一個(gè)窗口里,前一個(gè)網(wǎng)頁設(shè)置了這個(gè)屬性,后一個(gè)網(wǎng)頁可以讀取它。如果需要實(shí)現(xiàn)父頁面和跨域的子頁面之間的通信,需要一個(gè)和父頁面同源的子頁面作為中介,將跨域的子頁面中的信息傳遞過來。(好麻煩呀,強(qiáng)烈不推薦使用,此處就不寫對應(yīng)的代碼啦)
document.domain
document.domain是存放文檔的服務(wù)器的主機(jī)名,可通過手動(dòng)設(shè)置將其設(shè)置成當(dāng)前域名或者上級的域名,當(dāng)具有相同document.domain的頁面就相當(dāng)于處于同域名的服務(wù)器上,如果其域名和端口號相同就可以實(shí)現(xiàn)跨域訪問數(shù)據(jù)了。
postMessage(強(qiáng)烈推薦)
window.postMessage是HTML5新增的跨文檔通信API,該API,允許跨窗口通信,不論這兩個(gè)窗口是否同源。
- // 父頁面
- 我是父頁面
- window.addEventListener('message', function(event) {
- console.log('父頁面接收到信息', event.data);
- });
- document.getElementById('btn').addEventListener('click', () => {
- const iframeDom = document.getElementById('childHtmlId');
- iframeDom.contentWindow.postMessage('我是執(zhí)鳶者1', 'http://127.0.0.1:5500/024/childHtml1.html');
- });
- // 子頁面
- 我是子頁面
- window.addEventListener('message', function(event) {
- console.log('子頁面接收到信息', event.data);
- });
- document.getElementById('btn').addEventListener('click', () => {
- parent.postMessage('我是執(zhí)鳶者2', 'http://127.0.0.1:5500/024/parentHtml1.html');
- });
25.2.2 網(wǎng)絡(luò)層面
根據(jù)同源策略,瀏覽器默認(rèn)是不允許XMLHttpRequest對象訪問非同一站點(diǎn)的資源的,這會(huì)大大制約生產(chǎn)力,所以需要破解這種限制,實(shí)現(xiàn)跨域訪問資源。目前廣泛采用的主要有三種方式(注:該出不給出具體代碼,后續(xù)會(huì)有專門的百題斬進(jìn)行詳細(xì)闡述):
通過代理實(shí)現(xiàn)
同源策略是瀏覽器為了安全制定的策略,所以服務(wù)端不會(huì)存在這樣的限制,這樣我們就可以將請求打到同源的服務(wù)器上,然后經(jīng)由同源服務(wù)器代理至最終需要的服務(wù)器,從而實(shí)現(xiàn)跨域請求的目的。例如可以通過Nginx、Node中間件等。
JSONP的方式(具體實(shí)現(xiàn)見后續(xù)百題斬)
JSONP是一種借助script元素實(shí)現(xiàn)跨域的技術(shù),它并沒有使用XMLHttpRequest對象,其能夠?qū)崿F(xiàn)跨域主要得益于script有兩個(gè)特點(diǎn):
(1)src屬性能夠訪問任何URL資源,并不會(huì)受到同源策略的限制;
(2)如果訪問的資源包含JavaScript代碼,其會(huì)在下載后自動(dòng)執(zhí)行。
CORS方式(具體實(shí)現(xiàn)見后續(xù)百題斬)
跨域資源共享(CORS),該機(jī)制可以進(jìn)行跨域訪問控制,從而使跨域數(shù)據(jù)傳輸?shù)靡园踩M(jìn)行。(實(shí)現(xiàn)一個(gè)跨域請求的方式,其中html訪問網(wǎng)址為http://127.0.0.1:8009; 服務(wù)器監(jiān)聽端口為:8010)
(1)html頁面內(nèi)容
test CORS - CORS
- axios('http://127.0.0.1:8010', {
- method: 'get'
- }).then(console.log)
(2)服務(wù)器端代碼
- const express = require('express');
- const app = express();
- app.get('/', (req, res) => {
- console.log('get請求收到了?。?!');
- res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8009');
- res.send('get請求已經(jīng)被處理');
- })
- app.listen(8010, () => {
- console.log('8010 is listening')
- });
本文轉(zhuǎn)載自微信公眾號「執(zhí)鳶者」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系執(zhí)鳶者公眾號。
文章名稱:前端百題斬之原來跨域也是可以進(jìn)行分類的
路徑分享:http://fisionsoft.com.cn/article/dpcoeeg.html


咨詢
建站咨詢
