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

關於前端跨域總結的相關知識點

May 21, 2018 pm 04:41 PM

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

前言

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

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

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1323
25
PHP教程
1272
29
C# 教程
1251
24
總結Linux系統中system()函數的用法 總結Linux系統中system()函數的用法 Feb 23, 2024 pm 06:45 PM

Linux下system()函數的總結在Linux系統中,system()函數是一個非常常用的函數,它可以用來執行命令列指令。本文將對system()函數進行詳細的介紹,並提供一些特定的程式碼範例。一、system()函數的基本用法system()函數的聲明如下:intsystem(constchar*command);其中,command參數是一個字符

PHP Session 跨域問題的解決方法 PHP Session 跨域問題的解決方法 Oct 12, 2023 pm 03:00 PM

PHPSession跨域問題的解決方法在前後端分離的開發中,跨域請求已成為常態。在處理跨域問題時,我們通常會涉及session的使用和管理。然而,由於瀏覽器的同源策略限制,跨域情況下預設無法共享session。為了解決這個問題,我們需要採用一些技巧和方法來實現session的跨域共享。一、使用cookie跨域共享session最常

PHP與Vue:完美搭檔的前端開發利器 PHP與Vue:完美搭檔的前端開發利器 Mar 16, 2024 pm 12:09 PM

PHP與Vue:完美搭檔的前端開發利器在當今網路快速發展的時代,前端開發變得愈發重要。隨著使用者對網站和應用的體驗要求越來越高,前端開發人員需要使用更有效率和靈活的工具來創建響應式和互動式的介面。 PHP和Vue.js作為前端開發領域的兩個重要技術,搭配起來可以稱得上是完美的利器。本文將探討PHP和Vue的結合,以及詳細的程式碼範例,幫助讀者更好地理解和應用這兩

Django是前端還是後端?一探究竟! Django是前端還是後端?一探究竟! Jan 19, 2024 am 08:37 AM

Django是一個由Python編寫的web應用框架,它強調快速開發和乾淨方法。儘管Django是web框架,但要回答Django是前端還是後端這個問題,需要深入理解前後端的概念。前端是指使用者直接和互動的介面,後端是指伺服器端的程序,他們透過HTTP協定進行資料的互動。在前端和後端分離的情況下,前後端程式可以獨立開發,分別實現業務邏輯和互動效果,資料的交

Go語言前端技術探秘:前端開發新視野 Go語言前端技術探秘:前端開發新視野 Mar 28, 2024 pm 01:06 PM

Go語言作為一種快速、高效的程式語言,在後端開發領域廣受歡迎。然而,很少有人將Go語言與前端開發聯繫起來。事實上,使用Go語言進行前端開發不僅可以提高效率,還能為開發者帶來全新的視野。本文將探討使用Go語言進行前端開發的可能性,並提供具體的程式碼範例,幫助讀者更了解這一領域。在傳統的前端開發中,通常會使用JavaScript、HTML和CSS來建立使用者介面

C#開發經驗分享:前端與後端協同開發技巧 C#開發經驗分享:前端與後端協同開發技巧 Nov 23, 2023 am 10:13 AM

身為C#開發者,我們的開發工作通常包括前端和後端的開發,而隨著技術的發展和專案的複雜性提高,前端與後端協同開發也變得越來越重要和複雜。本文將分享一些前端與後端協同開發的技巧,以幫助C#開發者更有效率地完成開發工作。確定好介面規範前後端的協同開發離不開API介面的交互。要確保前後端協同開發順利進行,最重要的是定義好介面規格。接口規範涉及到接口的命

Django:前端和後端開發都能搞定的神奇框架! Django:前端和後端開發都能搞定的神奇框架! Jan 19, 2024 am 08:52 AM

Django:前端和後端開發都能搞定的神奇框架! Django是一個高效、可擴展的網路應用程式框架。它能夠支援多種Web開發模式,包括MVC和MTV,可以輕鬆地開發出高品質的Web應用程式。 Django不僅支援後端開發,還能夠快速建構出前端的介面,透過模板語言,實現靈活的視圖展示。 Django把前端開發和後端開發融合成了一種無縫的整合,讓開發人員不必專門學習

前端面試官常問的問題 前端面試官常問的問題 Mar 19, 2024 pm 02:24 PM

在前端開發面試中,常見問題涵蓋廣泛,包括HTML/CSS基礎、JavaScript基礎、框架和函式庫、專案經驗、演算法和資料結構、效能最佳化、跨域請求、前端工程化、設計模式以及新技術和趨勢。面試官的問題旨在評估候選人的技術技能、專案經驗以及對行業趨勢的理解。因此,應試者應充分準備這些方面,以展現自己的能力和專業知識。

See all articles