搜尋
首頁web前端js教程關於前端跨域總結的相關知識點

本篇對跨域進行了相關的講解。

前言

關於前端跨域的解決方法的多種多樣實在讓人目不暇接。以前碰到一個公司面試的場景是這樣的,好幾個人一起在等待面試,一個個進去面,面試官問:“給我說說跨域的解決方式吧”,吧啦吧啦就說出了(自己在當時情況下腦子裡能記住的)三種,然後面試官就說:“你們每個人進來都說了這三種,除了這些,還有哪些?”,頓時凌亂在風中...碰到這種情況,只能自己總結一篇博客,以備查漏補缺。

1. 什麼是跨域?

跨域一詞從字面意思看,就是跨域名嘛,但實際上跨域的範圍絕對不止那麼狹隘。具體概念如下:只要協定、網域名稱、連接埠有任何一個不同,都被當作是不同的網域。之所以會產生跨域這個問題呢,其實也很容易想明白,要是隨便引用外部文件,不同標籤下的頁面引用類似的彼此的文件,瀏覽器很容易懵逼的,安全也得不到保障了就。什麼事,都是安全第一嘛。但在安全限制的同時也為注入iframe或ajax應用上帶來了不少麻煩。所以我們要透過一些方法讓本域的js能夠操作其他域的頁面物件或是讓其他域的js能操作本域的頁面物件(iframe之間)。下面是具體的跨域情況詳解:

         URL                                                                         說明                                                                                                                                                        是否允許通信
http://www.a.com/a.jshttp://www.a.com/b.js            同一域名下           允許http://www.a.com/lab/a.jshttp://www.a.com/script/b.js  同一網域下不同資料夾     允許http://www.a.com:8000/ a.jshttp://www.a.com/b.js         同一域名,不同連接埠        適用於http://www.a.com/a.jshttps://www.a.com/b.js        相同域名,https://www.a.com/b.js      不同協定       不允許http://www.a.com/a.jshttp://70.32.92.74/b.js       網域名稱與網域對應ip         不允許http://www.a.com/a.jshttpip         不允許http://www.a.com/a.jshttpip script.a.com/b.js      主域相同,子網域不同       不允許(cookie此情況也不允許存取)http://www.a.com/a.jshttp://a.com/b .js             同一域名,不同二級域名(同上) 不允許(cookie這種情況下也不允許訪問)http://www.cnblogs.com/a.jshttp://www.a.com/b.js不同網域                 不允許

需要注意兩點:

如果是協定和連接埠造成的跨域問題「前台」是無能為力的;

在跨領域域問題問題上,域只是透過「URL的首部」來辨識而不會去嘗試判斷相同的ip位址對應著兩個域或兩個域是否在同一個ip上。
(“URL的首部”指window.location.protocol window.location.host,也可以理解為“Domains, protocols and ports must match”。)

#同源策略

############# #同網域(或ip),同端口,同協議視為同一個域;一個域內的腳本僅具有本域內的權限,可以理解為本域腳本只能讀寫本域內的資源,而無法訪問其它域的資源。這種安全限制稱為同源策略。 ######同源策略是瀏覽器最基本的安全功能。如果沒有同源策略,那麼普通用戶將沒有安全可言。使用者的所有私密資訊都可以被任何人取得,例如網站的Cookie、email的郵件內容。也容易遭受CSRF攻擊。 ######要注意的是,域名和域名對應ip是不同來源的;主域名相同,子域名不相同也是不同來源的。 ######跨域解決方式(總結)######1. document.domain跨域###

前面說了,瀏覽器有一個同源策略,其限制之一是不能透過ajax的方法去請求不同來源中的文件。第二個限制是瀏覽器中不同網域的框架之間是不能進行js的互動操作的。
不同的框架之間是可以取得window物件的,但卻無法取得對應的屬性和方法。
例如,有一個頁面,它的位址是http://www.damonare.cn/a.html , 在這個頁面裡面有一個iframe,它的src是http://damonare.cn/b.html , 很顯然,這個頁面與它裡面的iframe框架是不同域的,所以我們是無法通過在頁面中這樣書寫js代碼來獲取iframe中的東西的:

<script type="text/javascript">
    function test(){        var iframe = document.getElementById(&#39;ifame&#39;);
   var win = document.contentWindow; //可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
        var doc = win.document; //这里获取不到iframe里的document对象
        var name = win.name; //这里同样获取不到window对象的name属性
    }</script><iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe>

這個時候,document.domain就可以派上用場了,我們只要把http://www.damonare.cn/a.html和http://damonare.cn/b.html這兩個頁面的document.domain都設成相同的網域就可以了。

注意: document.domain的設定是有限制的,我們只能把document.domain設定成自身或更高一級的父域,且主域必須相同。

在頁面http://www.damonare.cn/a.html 中設定document.domain:

<iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe><script type="text/javascript">
    document.domain = &#39;damonare.cn&#39;;//设置成主域
    function test(){        //contentWindow 可取得子窗口的 window 对象
        alert(document.getElementById(&#39;iframe&#39;).contentWindow);
    }</script>

在頁面http://damonare.cn/b.html 中也設定document.domain:


修改document.domain的方法只適用於不同子域的框架間的交互作用。

2. 透過location.hash跨域

因為父視窗可以對iframe進行URL讀寫,iframe也可以讀寫父視窗的URL,URL有一部分被稱為hash,就是#號及其後面的字符,它一般用於瀏覽器錨點定位,Server端並不關心這部分,應該說HTTP請求過程中不會攜帶hash,所以這部分的修改不會產生HTTP請求,但是會產生瀏覽器歷史記錄。此方法的原理就是改變URL的hash部分來進行雙向通訊。每個window透過改變其他window的location來傳送訊息(由於兩個頁面不在同一個網域下IE、Chrome不允許修改parent.location.hash的值,所以要藉助於父視窗網域下的一個代理iframe),並透過監聽自己的URL的變化來接收訊息。這個方式的通訊會造成一些不必要的瀏覽器歷史記錄,而且有些瀏覽器不支援onhashchange事件,需要輪詢來獲知URL的改變,最後,這樣做也存在缺點,諸如數據直接暴露在了url中,資料容量和類型都有限等。

舉例說明:
假如父頁面是baidu.com/a.html,iframe嵌入的頁面為google.com/b.html(此處省略了網域等url屬性),要實現此兩個頁間的通訊可以透過以下方法:

a.html傳送資料到b.html

a.html下修改iframe的src為google.com/b.html#paco

b.html監聽到url發生變化,觸發對應動作

b.html傳送資料到a.html,由於兩個頁面不在同一個網域下IE、Chrome不允許修改parent .location.hash的值,所以要藉助於父視窗網域下的一個代理iframe

b.html下建立一個隱藏的iframe,此iframe的src是baidu.com網域下的,並掛上要傳送的hash數據,如src=”http://www.baidu.com/proxy.html#data”

proxy.html監聽到url發生變化,修改a.html的url(因為a .html和* proxy.html同域,所以proxy.html可修改a.html的url hash)

a.html監聽到url發生變化,觸發對應操作

b.html頁面的關鍵程式碼如下:

try {  
    parent.location.hash = &#39;data&#39;;  
} catch (e) {  
    // ie、chrome的安全机制无法修改parent.location.hash,  
    var ifrproxy = document.createElement(&#39;iframe&#39;);  
    ifrproxy.style.display = &#39;none&#39;;  
    ifrproxy.src = "http://www.baidu.com/proxy.html#data";  
    document.body.appendChild(ifrproxy);  
}

proxy.html頁面的關鍵程式碼如下:

#/**
*因為parent.parent(即baidu.com/a.html)和baidu.com/proxy.html屬於同一個網域,
所以可以改變其location.hash的值**/  parent.parent.location.hash = self.location.hash. substring(1);

3. 透過HTML5的postMessage方法跨網域

進階瀏覽器IE8 , chrome,Firefox , Opera 和Safari 都會支援這個功能。
這個功能主要包括接受訊息的”message」事件和發送訊息的”postMessage」方法。
例如damonare.cn域的A頁面透過iframe嵌入了一個google.com域的B頁面,可以透過以下方法實作A和B的通訊:

A頁面透過postMessage方法傳送訊息:

window.onload = function() {  
    var ifr = document.getElementById(&#39;ifr&#39;);  
    var targetOrigin = "http://www.google.com";  
    ifr.contentWindow.postMessage(&#39;hello world!&#39;, targetOrigin);  
};

postMessage的使用方法:otherWindow.postMessage(message, targetOrigin);

otherWindow:指目標窗口,也就是給哪個window發訊息,是window.frames 屬性的成員或是由window .open 方法所建立的視窗。

message: 是要傳送的訊息,類型為 String、Object (IE8、9 不支援)。

targetOrigin: 是限定訊息接收範圍,不限制請使用 ' * '。

B頁面透過message事件監聽並接受訊息:

var onmessage = function (event) {  
  var data = event.data;//消息  
  var origin = event.origin;//消息来源地址  
  var source = event.source;//源Window对象  
  if(origin=="http://www.baidu.com"){  
console.log(data);//hello world!  
  }  
};  
if (typeof window.addEventListener != &#39;undefined&#39;) {  
  window.addEventListener(&#39;message&#39;, onmessage, false);  
} else if (typeof window.attachEvent != &#39;undefined&#39;) {  
  //for ie  
  window.attachEvent(&#39;onmessage&#39;, onmessage);  
}

同理,也可以B頁面傳送訊息,然後A頁面監聽並接受訊息。

4. jsonp跨域

以上的这几种都是双向通信的,即两个iframe,页面与iframe,或是页面与页面之间的。
下面说几种单向跨域的(一般用来获取数据),因为通过script标签引入的js是不受同源策略的限制的。
所以我们可以通过script标签引入一个js或者是一个其他后缀形式(如php,jsp等)的文件,此文件返回一个js函数的调用。

比如,有个a.html页面,它里面的代码需要利用ajax获取一个不同域上的json数据,假设这个json数据地址是http://damonare.cn/data.php,那么a.html中的代码就可以这样:


可以看到获取数据的地址后面还有一个callback参数,按惯例是用这个参数名,但是你用其他的也一样。当然如果获取数据的jsonp地址页面不是你自己能控制的,就得按照提供数据的那一方的规定格式来操作了。
因为是当做一个js文件来引入的,所以http://damonare.cn/data.php返回的必须是一个能执行的js文件,所以这个页面的php代码可能是这样的(一定要和后端约定好哦):

 $callback = $_GET['callback'];//得到回调函数名
 $data = array('a','b','c');//要返回的数据
 echo $callback.'('.json_encode($data).')';//输出?>

最终,输出结果为:dosomething([‘a’,’b’,’c’]);

如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了:

<script type="text/javascript">
    $.getJSON(&#39;http://example.com/data.php?callback=?,function(jsondata)&#39;){        //处理获得的json数据
    });</script>

jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。
$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。

JSONP的优缺点:

JSONP的优点:
它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。

JSONP的缺点:
它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

5. CORS跨域

CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。
CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。
对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

平时的ajax请求可能是这样的:

<script type="text/javascript">
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/damonare",true);
    xhr.send();</script>

以上damonare部分是相对路径,如果我们要使用CORS,相关Ajax代码可能如下所示:

<script type="text/javascript">
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://segmentfault.com/u/andreaxiang/",true);
    xhr.send();</script>

代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。

服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。
如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
关于CORS更多了解可以看下阮一峰老师的这一篇文章:跨域资源共享 CORS 详解

CORS和JSONP对比

JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。

使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。

JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。

CORS与JSONP相比,无疑更为先进、方便和可靠。

6. 通过window.name跨域

window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
比如:我们在任意一个页面输入

window.name = "My window&#39;s name";
setTimeout(function(){    window.location.href = "http://damonare.cn/";
},1000)

进入damonare.cn页面后我们再检测再检测 window.name :
window.name; // My window's name

可以看到,如果在一个标签里面跳转网页的话,我们的 window.name 是不会改变的。
基于这个思想,我们可以在某个页面设置好 window.name 的值,然后跳转到另外一个页面。在这个页面中就可以获取到我们刚刚设置的 window.name 了。

由于安全原因,浏览器始终会保持 window.name 是string 类型。

同样这个方法也可以应用到和iframe的交互来,比如:
我的页面(http://damonare.cn/index.html)中内嵌了一个iframe:

在 iframe.html 中设置好了 window.name 为我们要传递的字符串。
我们在 index.html 中写了下面的代码:

var iframe = document.getElementById(&#39;iframe&#39;);var data = &#39;&#39;;
iframe.onload = function() {
    data = iframe.contentWindow.name;
};

报错!肯定的,因为两个页面不同源嘛,想要解决这个问题可以这样干:

var iframe = document.getElementById(&#39;iframe&#39;);var data = &#39;&#39;;
 
iframe.onload = function() {
    iframe.onload = function(){
        data = iframe.contentWindow.name;
    }
    iframe.src = &#39;about:blank&#39;;
};

或者将里面的 about:blank 替换成某个同源页面(about:blank,javascript: 和 data: 中的内容,继承了载入他们的页面的源。)

这种方法与 document.domain 方法相比,放宽了域名后缀要相同的限制,可以从任意页面获取 string 类型的数据。

本篇对跨域做出相应的总结,更多相关知识请关注php中文网。

相关推荐:

前端常见跨域解决方案(全)

什么是跨域?跨域有几种实现形式?

对于函数事件的总结

以上是關於前端跨域總結的相關知識點的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
5个常见的JavaScript内存错误5个常见的JavaScript内存错误Aug 25, 2022 am 10:27 AM

JavaScript 不提供任何内存管理操作。相反,内存由 JavaScript VM 通过内存回收过程管理,该过程称为垃圾收集。

巧用CSS实现各种奇形怪状按钮(附代码)巧用CSS实现各种奇形怪状按钮(附代码)Jul 19, 2022 am 11:28 AM

本篇文章带大家看看怎么使用 CSS 轻松实现高频出现的各类奇形怪状按钮,希望对大家有所帮助!

Node.js 19正式发布,聊聊它的 6 大特性!Node.js 19正式发布,聊聊它的 6 大特性!Nov 16, 2022 pm 08:34 PM

Node 19已正式发布,下面本篇文章就来带大家详解了解一下Node.js 19的 6 大特性,希望对大家有所帮助!

实战:vscode中开发一个支持vue文件跳转到定义的插件实战:vscode中开发一个支持vue文件跳转到定义的插件Nov 16, 2022 pm 08:43 PM

vscode自身是支持vue文件组件跳转到定义的,但是支持的力度是非常弱的。我们在vue-cli的配置的下,可以写很多灵活的用法,这样可以提升我们的生产效率。但是正是这些灵活的写法,导致了vscode自身提供的功能无法支持跳转到文件定义。为了兼容这些灵活的写法,提高工作效率,所以写了一个vscode支持vue文件跳转到定义的插件。

浅析Vue3动态组件怎么进行异常处理浅析Vue3动态组件怎么进行异常处理Dec 02, 2022 pm 09:11 PM

Vue3动态组件怎么进行异常处理?下面本篇文章带大家聊聊Vue3 动态组件异常处理的方法,希望对大家有所帮助!

聊聊如何选择一个最好的Node.js Docker镜像?聊聊如何选择一个最好的Node.js Docker镜像?Dec 13, 2022 pm 08:00 PM

选择一个Node​的Docker镜像看起来像是一件小事,但是镜像的大小和潜在漏洞可能会对你的CI/CD流程和安全造成重大的影响。那我们如何选择一个最好Node.js Docker镜像呢?

聊聊Node.js中的 GC (垃圾回收)机制聊聊Node.js中的 GC (垃圾回收)机制Nov 29, 2022 pm 08:44 PM

Node.js 是如何做 GC (垃圾回收)的?下面本篇文章就来带大家了解一下。

【6大类】实用的前端处理文件的工具库,快来收藏吧!【6大类】实用的前端处理文件的工具库,快来收藏吧!Jul 15, 2022 pm 02:58 PM

本篇文章给大家整理和分享几个前端文件处理相关的实用工具库,共分成6大类一一介绍给大家,希望对大家有所帮助。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。