1. 程式人生 > >Web開發中跨域的幾種解決方案

Web開發中跨域的幾種解決方案

隨著Web App的功能越來越強 各種跨域的需求催生了無數的跨域手法。甚至在HTML5標準中都給出了官方的跨域方法, 也是最近應付面試的需要,拿一篇文章來總結既有的各種跨域手段。

這些跨域通訊的方法大致可以分為兩類:

  • 一類是Hack,比如通過titlenavigation等物件傳遞資訊,JSONP可以說是一個最優秀的Hack。
  • 另一類是HTML5支援,一個是Access-Control-Allow-Origin響應頭,一個是window.postMessage

設定 document.domain

  • 原理:相同主域名不同子域名下的頁面,可以設定document.domain讓它們同域
  • 限制:同域document提供的是頁面間的互操作,需要載入iframe頁面

下面幾個域名下的頁面都是可以通過document.domain跨域互操作的: http://a.com/foohttp://b.a.com/barhttp://c.a.com/bar。 但只能以頁面巢狀的方式來進行頁面互操作,比如常見的iframe方式就可以完成頁面巢狀:

// URL http://a.com/foo
var ifr = document.createElement('iframe');
ifr.src = 'http://b.a.com/bar'; 
ifr.onload = function(){
    var ifrdoc = ifr.contentDocument || ifr.contentWindow
.document; ifrdoc.getElementsById("foo").innerHTML); }; ifr.style.display = 'none'; document.body.appendChild(ifr);

上述程式碼所在的URL是http://a.com/foo,它對http://b.a.com/bar的DOM訪問要求後者將 document.domain往上設定一級:

// URL http://b.a.com/bar
document.domain = 'a.com'

document.domain只能從子域設定到主域,往下設定以及往其他域名設定都是不允許的, 在Chrome中給出的錯誤是這樣的:

Uncaught DOMException: Failed to set the 'domain' property on 'Document': 'baidu.com' is not a suffix of 'b.a.com'

有src的標籤

  • 原理:所有具有src屬性的HTML標籤都是可以跨域的,包括<img><script>
  • 限制:需要建立一個DOM物件,只能用於GET方法

document.bodyappend一個具有src屬性的HTML標籤, src屬性值指向的URL會以GET方法被訪問,該訪問是可以跨域的。

其實樣式表的<link>標籤也是可以跨域的,只要是有srchref的HTML標籤都有跨域的能力。

不同的HTML標籤傳送HTTP請求的時機不同,例如<img>在更改src屬性時就會發送請求,而scriptiframelink[rel=stylesheet]只有在新增到DOM樹之後才會傳送HTTP請求:

var img = new Image();
img.src = 'http://some/picture';        // 傳送HTTP請求

var ifr = $('<iframe>', {src: 'http://b.a.com/bar'});
$('body').append(ifr);                  // 傳送HTTP請求

JSONP

  • 原理:<script>是可以跨域的,而且在跨域指令碼中可以直接回調當前指令碼的函式。
  • 限制:需要建立一個DOM物件並且新增到DOM樹,只能用於GET方法

JSONP利用的是<script>可以跨域的特性,跨域URL返回的指令碼不僅包含資料,還包含一個回撥:

// URL: http://b.a.com/foo
var data = {
    foo: 'bar',
    bar: 'foo'
};
callback(data);

該例子只用於示例,實際情況應當考慮名稱隱藏等問題。

然後在我們在主站http://a.com中,可以這樣來跨域獲取http://b.a.com的資料:

// URL: http://a.com/foo
var callback = function(data){
    // 處理跨域請求得到的資料
};
var script = $('<script>', {src: 'http://b.a.com/bar'});
$('body').append(script);

其實jQuery已經封裝了JSONP的使用,我們可以這樣來:

$.getJSON( "http://b.a.com/bar?callback=callback", function( data ){
    // 處理跨域請求得到的資料
});

$.getJSON$.get的區別是前者會把responseText轉換為JSON,而且當URL具有callback引數時, jQuery將會把它解釋為一個JSONP請求,建立一個<script>標籤來完成該請求。

jQuery.getJSON: If the URL includes the string “callback=?” (or similar, as defined by the server-side API), the request is treated as JSONP instead. See the discussion of the jsonp data type in $.ajax() for more details.)

和所有依賴於建立HTML標籤的方式一樣,JSONP也不支援POST,而GET的資料是放在URL裡的。 雖然[RFC 2616][rfc2610]沒有提到限制到多少, 但提到了伺服器可以對自己認為比較長的URL返回414狀態碼。一般來講URL限長是在2000字元左右。

navigation 物件

  • 原理:iframe之間是共享navigator物件的,用它來傳遞資訊
  • 要求:IE6/7

有些人注意到了IE6/7的一個漏洞:iframe之間的window.navigator物件是共享的。 我們可以把它作為一個Messenger,通過它來傳遞資訊。比如一個簡單的委託:

// a.com
navigation.onData(){
    // 資料到達的處理函式
}
typeof navigation.getData === 'function' 
    || navigation.getData()
// b.com
navigation.getData = function(){
    $.get('/path/under/b.com')
        .success(function(data){
            typeof navigation.onData === 'function'
                || navigation.onData(data)
        });
}

document.navigator類似,window.name也是當前視窗所有頁面所共享的。也可以用它來傳遞資訊。 同樣蛋疼的辦法還有傳遞Hash(有些人叫錨點),這是因為每次瀏覽器開啟一個URL時,URL後面的#xxx部分會保留下來,那麼新的頁面可以從這裡獲得上一個頁面的資料。

跨域資源共享(CORS)

  • 原理:伺服器設定Access-Control-Allow-OriginHTTP響應頭之後,瀏覽器將會允許跨域請求
  • 限制:瀏覽器需要支援HTML5,可以支援POST,PUT等方法

前面提到的跨域手段都是某種意義上的Hack, HTML5標準中提出的跨域資源共享(Cross Origin Resource Share,CORS)才是正道。 它支援其他的HTTP方法如PUT, POST等,可以從本質上解決跨域問題。

例如,從http://a.com要訪問http://b.com的資料,通常情況下Chrome會因跨域請求而報錯:

XMLHttpRequest cannot load http://b.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://a.com' is therefore not allowed access.

錯誤原因是被請求資源沒有設定Access-Control-Allow-Origin,所以我們在b.com的伺服器中設定這個響應頭欄位即可:

Access-Control-Allow-Origin: *              # 允許所有域名訪問,或者
Access-Control-Allow-Origin: http://a.com   # 只允許所有域名訪問

為 xhr 設定 withCredentials 後 CORS 方法跨域還可 攜帶Cookie,但 PUT/POST 請求需要注意處理 preflight 請求

window.postMessage

  • 原理:HTML5允許視窗之間傳送訊息
  • 限制:瀏覽器需要支援HTML5,獲取視窗控制代碼後才能相互通訊

這是一個安全的跨域通訊方法,postMessage(message,targetOrigin)也是HTML5引入的特性。 可以給任何一個window傳送訊息,不論是否同源。第二個引數可以是*但如果你設定了一個URL但不相符,那麼該事件不會被分發。看一個普通的使用方式吧:

// URL: http://a.com/foo
var win = window.open('http://b.com/bar');
win.postMessage('Hello, bar!', 'http://b.com'); 
// URL: http://b.com/bar
window.addEventListener('message',function(event) {
    console.log(event.data);
});

訪問控制安全的討論

在HTML5之前,JSONP已經成為跨域的事實標準了,jQuery都給出了支援。 值得注意的是它只是Hack,並沒有產生額外的安全問題。 因為JSONP要成功獲取資料,需要跨域資源所在伺服器的配合,比如資源所在伺服器需要自願地回撥一個合適的函式,所以伺服器仍然有能力控制資源的跨域訪問。

跨域的正道還是要使用HTML5提供的CORS頭欄位以及window.postMessage, 可以支援POST, PUT等HTTP方法,從機制上解決跨域問題。 值得注意的是Access-Control-Allow-Origin頭欄位是資源所在伺服器設定的, 訪問控制的責任仍然是在提供資源的伺服器一方,這和JSONP是一樣的。

相關推薦

Web開發解決方案

隨著Web App的功能越來越強 各種跨域的需求催生了無數的跨域手法。甚至在HTML5標準中都給出了官方的跨域方法, 也是最近應付面試的需要,拿一篇文章來總結既有的各種跨域手段。 這些跨域通訊的方法大致可以分為兩類: 一類是Hack,比如通過title, navigation等物件傳遞資訊,JSONP可

解決方法

跨域 -o head 反向 content nbsp ces methods 函數 1.jsonp 目標服務器設置callback 函數 服務器操作 2.cors 服務器設置header :Access-Control-Allow-Origin 服務器操作

vue開發過程最簡單解決方案

前言:我們在進行一個專案開發工程中,需要從後端工程師那裡獲取資料庫中的資料。然而前端程式碼和後端程式碼在未打包前是分離的,這就引入了一個“跨域取資料”的問題。 下面,我們就簡單說下,利用vue腳手架生成的專案,在開發過程中怎麼解決此問題。 第一步 找到並開啟config資料夾下的index.js,做如下配置

web開發常用的統計圖使用

最近,筆者結合自己在公司專案使用統計圖的經驗以及自己的研究,對地圖統計、柱形圖統計、餅圖統計以及折線圖統計這幾種常用的統計作以歸納。主要使用到的js框架是highstock.js,一種完全基於javascript的前端框架。接下來,一一進行講解。 一、地圖

Web學習之問題及解決方案

在做前端開發時,我們時常使用ajax與伺服器通訊獲取資源,享受ajax便利的同時,也知道它有限制:跨域安全限制,即同源策略。 同源策略(SOP),核心是確保不同源提供的檔案之間是相互獨立的 預設情況下,XHR物件只能訪問與包含它的頁面處於同一域中的資源,這種限制可以預防某些惡意攻擊,但同

處理session方案

常用跨域共用session的是登入模組,我相信很多開發的朋友的都遇到過,只需要一個地方登入,相關聯的網站也是處於登入狀態。兩種情況:一種9streets.cn和a.9streets.cn之間,另一種是a.com b.com之間,這幾天總結了一下處理方法。 方式一:

thinkphp5/tp5介面開發問題的全部解決方案,options請求的處理

場景還原:由於前後端分離後有可能出現介面的url和我們前端訪問的url不再同一個域名下。這就會導致一個問題,就是瀏覽器的同源策略。對於同源策略如果要正常的使用我們就要處理跨域的問題。當然在跨域中介面傳送前會有一次OPTIONS請求,關於為什麼傳送OPTIONS

使用http-proxy-middleware解決前端開發的問題

一、使用http-proxy-middleware中介軟體解決跨域問題 本案例中使用基本的webpack及axios請求資料的外掛 1、後端服務是用tornado建立的一個服務(可以根據自

圖片上傳的問題的解決方案和細節及優缺點

方案一 傳到前端伺服器本地,然後用伺服器跨域 ajaxSubmit方式,需要jquery.form.min.js外掛 $("#imgUploadForm").ajaxSubmit({ type: "POST",//提交型別 dataType: "json"

iframe、ajax和JS通訊的解決方案

 需要ajax跨域取得資料,如果是在本域中確實沒有問題,但是放到二級域和其他域下瀏覽器直接就彈出提示框:“該頁正在訪問其控制範圍之外的資料,這有些危險,是否繼續"  1.什麼引起了ajax跨域不能的問題  ajax本身實際上是通過XMLHttpRequest物件來進行資

前端方式

div ner dev 修改 ati hash 標簽 nbsp 端口 跨域問題的直接原因是瀏覽器存在同源策略,瀏覽器同源指的是:兩個頁面的協議、端口和主機相同,則兩個頁面具有相同的源。IE下滿足協議、主機相同,就認為是同源。 想象一下,如果沒有同源策略,誰都可以修改你站點

Arcgis Server問題的解決辦法

arcgis server javascript api開發過程中,在跨域訪問字型、json、地圖服務等資源的時候,會遇到無法訪問的問題,如:“……blocked by CORS”,“……cannot load”,後面常跟一句“No ‘Access-Control-Allow-Origin’

Android第一天---開發常用的佈局

第一種:LinearLayout:線性佈局 線性佈局是按照處置或者水平進行排布的,預設是水平 屬性:orientation:用來指定當前的線性佈局的排布方向。 wrap_content:包裹內容 match_parent:匹配父類 margin:外邊距 padding

WPF開發常用的佈局元素

Grid:網格。可以自定義行和列並通過行列的數量、行高和行寬來調整控制元件的佈局,類似於HTML中的Table。 StackPanel:棧式模板。可將包含的元素在豎直或水平方向上排成一條直線,當移除一個元素後,後面的元素會自動向前移動以填充空缺。 Canvas:畫布。內部元素可以使用以畫素為單位的絕對座標

vue-cli 開發問題和profile模式配置

一、開發環境中跨域   使用 Vue-cli 建立的專案,開發地址是 localhost:8080,需要訪問非本機上的介面http://10.1.0.34:8000/queryRole。不同域名之間的訪問,需要跨域才能正確請求。跨域的方法很多,通常都需要後臺配置,不過 Vue-cli 建立的

SpringBoot:SpringBoot專案問題的解決

SpringBoot:SpringBoot專案中跨域問題的解決 出於安全原因,瀏覽器禁止對駐留在當前源之外的資源進行AJAX呼叫。 跨源資源共享(CORS)是大多數瀏覽器實現的W3C規範,允許以靈活的方式指定授權的跨域請求型別,而不是使用IFrame或JSON

方式

一、什麼是跨域 JavaScript出於安全方面的考慮,不允許跨域呼叫其他頁面的物件。那什麼是跨域呢,簡單地理解就是因為JavaScript同源策略的限制, a.com 域名下的js無法操作 b.com 或是 c.a.com 域名下的物件。 有一點必須要注意:

web 專案解決問題終極解決方案

一.跨域問題的由來 二.怎麼就算跨域(同源的定義) 三.常見跨域解決方法 四.總結 一.跨域問題的由來 為什麼會產生這樣一個問題,擺在我們面前呢?? 理解跨域,首先必須要了解同源策略。同源策略是瀏覽器上為安全性考慮實施的非常重要的安全策略。 為了防止某些文件或指令碼載入別

分類任務資料類別不平衡問題的解決方案

類別不平衡(class-imbalance),是指分類任務中不同類別的訓練樣例數目差別很大的情況(例如,訓練集正類樣例10個,反類樣例90個),本文假設正類樣例較少,反類樣例較多。 現有解決方案大體分為三類,如下文所示。 欠取樣(undersampling) 欠取樣方法,即去除一

SpringBoot問題的解決

什麼叫跨域 瀏覽器對於javascript的同源策略的限制,例如a.cn下面的js不能呼叫b.cn中的js,物件或資料(因為a.cn和b.cn是不同域),所以跨域就出現了.簡而言之,就是本地伺服器不能呼叫其他伺服器的資源。 導致的問題: web端收不到伺服器端的返回訊