2010-04-01 162 views
64

我瞭解AJAX跨域策略。 因此,我不能只通過ajax HTTP請求調用「http://www.google.com」,並在我的網站某處顯示 結果。AJAX跨域調用

我的dataType「JSONP」試了一下,實際上會工作,但我得到一個語法錯誤(顯然是因爲接收到的數據是不是JSON格式化)

是否有任何其他方法可行,從接收/顯示數據一個外地? iFrames遵循相同的政策?

回答

63

使用AJAX獲取跨域數據的唯一(簡單)方式是使用服務器端語言作爲代理,如Andy E所述。下面是一個小樣本如何實現使用jQuery是:

jQuery的部分:

$.ajax({ 
    url: 'proxy.php', 
    type: 'POST', 
    data: { 
     address: 'http://www.google.com' 
    }, 
    success: function(response) { 
     // response now contains full HTML of google.com 
    } 
}); 

而PHP(proxy.php):

echo file_get_contents($_POST['address']); 

這麼簡單。只要知道你可以或不可以用刮取的數據做什麼。

+28

而且要非常清楚,這樣的代理是一個嚴重的安全漏洞......至少要列出可接受的地址,不要盲目接受任何通過的地址。 看看一個體面的代理腳本在這裏:http://benalman.com/projects/php-simple-proxy/ – 2010-08-27 14:41:31

+1

但是,當目標頁面有非絕對URL和相對鏈接時,它不會破壞佈局嗎? – Mori 2013-11-29 06:47:46

+0

@ChristianStuder爲什麼這有問題? – John 2016-05-23 07:12:32

18

您需要動態地將腳本標記插入到引用數據的頁面中。使用JSONP,您可以在加載腳本時執行一些回調函數。

JSONP上的維基百科頁面有一個簡潔的例子;該腳本標籤:

<script type="text/javascript" src="http://domain1.com/getjson?jsonp=parseResponse"> 
</script> 

將包裹在一個呼叫JSON數據返回parseResponse

parseResponse({"Name": "Cheeso", "Rank": 7}) 

(取決於getjson腳本的配置上domain1.com)

的代碼要動態插入標籤會是這樣的:

var s = document.createElement("script"); 
s.src = "http://domain1.com/getjson?jsonp=parseResponse"; 
s.type = "text/javascript"; 
document.appendChild(s); 
+0

只有當您收到JSON數據或純文本或HTML格式時,這纔會起作用嗎? – jAndy 2010-04-01 08:19:38

+1

@jAndy:這隻適用於JSONP(包括回調函數)數據。 – 2010-04-01 08:21:37

+0

只適用於GET請求。沒有PUT,DELETE或POST。所以沒有RESTful接口。 – ProblemsOfSumit 2015-08-11 13:09:49

2

在我看來,JSONP是最好的選擇。試着弄清楚爲什麼你會得到語法錯誤 - 你確定收到的數據不是JSON嗎?那麼也許你以某種方式錯誤地使用了API。

您可以使用的另一種方式,但我不認爲它適用於您的情況,是在頁面中有一個iFrame,src位於您要調用的域中。讓它爲您打電話,然後使用JS在iFrame和頁面之間進行通信。這將繞過跨域,但前提是您可以在要調用的域中擁有iFrame的src。

+1

@Nir:他得到了語法錯誤,因爲他在提取HTML而不是JSON。這將永遠不會與JSONP一起工作:-) – 2010-04-01 08:17:04

11

不幸的是(或幸運的是)沒有。跨域策略是有原因的,如果它很容易繞過它,那麼它作爲安全措施就不是很有效。除了JSONP,唯一的選擇是proxy the pages using your own server

使用iframe時,它們受制於相同的策略。當然,您可以顯示來自外部域的數據,但您無法操作它。

+0

你是什麼意思,「你不能操縱它」? 你不能將一些數據加載到iFrame中,並通過jQuery選擇器讀取數據? – jAndy 2010-04-01 08:50:36

+4

@jAndy:不,在訪問跨不同域的文檔時,訪問被阻止到DOM的99%。跨文檔消息傳遞是可能的(使用HTML5 /現代瀏覽器),但必須由雙方實施。 – 2010-04-01 08:56:29

4

做一些研究之後,唯一的「解決方案」這個問題是調用:

if($.browser.mozilla) 
    netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead'); 

這會問一個用戶,如果他讓網站繼續。在他確認後,所有 ajax調用,不管它的數據類型是否會被執行。

這適用於Mozilla瀏覽器,在IE < 8中,用戶必須以類似方式允許跨域調用 ,某些版本需要在瀏覽器選項中進行配置。

chrome/safari:到目前爲止,我沒有找到這些瀏覽器的配置標誌。

使用JSONP作爲數據類型會很好,但在我的情況下,我不知道我是否需要 來訪問該格式的數據。

另一種方法是使用HTML5 postMessage,它可以跨域使用,但我不能使用我的用戶訪問HTML5瀏覽器。

+14

您並未將您的用戶推向HTML5瀏覽器,您正在爲他們提供服務:-) – 2010-08-27 14:39:24

-3

我在2天內遇到了同樣的問題,並且找到了解決方案,並且Google搜索後很優雅。 我需要一些小部件客戶端的xss Ajax,這些小部件客戶端將數據流從層網站拉到我的Rails應用程序。 here's how I did.

4

我使用這段代碼進行跨域ajax調用,我希望它能幫助多個這裏。我使用Prototype庫,你可以做與jQuery或道場或別的相同:

第1步:創建一個新的js文件,並把這個類裏面,我把它叫做xss_ajax.js

var WSAjax = Class.create ({ 
    initialize: function (_url, _callback){ 
     this.url = _url ; 
     this.callback = _callback ; 
     this.connect() ; 
    }, 
    connect: function(){ 
     var script_id = null; 
     var script = document.createElement('script'); 
     script.setAttribute('type', 'text/javascript'); 
     script.setAttribute('src', this.url); 
     script.setAttribute('id', 'xss_ajax_script'); 

     script_id = document.getElementById('xss_ajax_script'); 
     if(script_id){ 
      document.getElementsByTagName('head')[0].removeChild(script_id); 
     } 

     // Insert <script> into DOM 
     document.getElementsByTagName('head')[0].appendChild(script); 
    }, 
    process: function (data){ 
     this.callback(data) ; 
    } 

}) ; 

該類創建一個動態腳本元素,其src屬性針對您的JSON數據提供者(實際上,因爲您的遠程服務器必須以此格式提供數據:: call_back_function(// json_data_here)::因此當創建腳本標記時你的JSON將作爲一個函數被直接撤銷(我們將在第2步中討論將回調方法名稱傳遞給服務器),其背後的主要概念是像img元素這樣的腳本不受SOP約束的影響。

第二步:在任何HTML頁面,你想拉JSON異步(我們稱之爲〜AJAJ異步JavaScript + JSON :-),而不是AJAX其使用XHTTPRequest對象)不喜歡下面

//load Prototype first 
//load the file you've created in step1 


var xss_crawler = new WSAjax (
    "http://your_json_data_provider_url?callback=xss_crawler.process" 
, function (_data){ 
      // your json data is _data and do whatever you like with it 
     }) ; 

d '你在第1步回覆回調?所以我們將它傳遞給服務器,它將返回嵌入在該方法中的JSON,所以在我們的例子中,服務器將返回一個可消除的JavaScript代碼xss_crawler.process(// the_json_data),請記住,xss_crawler是WSAjax類的一個實例。服務器代碼取決於你(如果它是你的),但是大部分Ajax數據提供者都允許你像參數那樣在參數中指定回調方法。 在Ruby on Rails的我只是做了

render :json=>MyModel.all(:limit=>10), :callback => params[:callback],:content_type => "application/json" 

,這一切,現在你可以從你的應用程序(小工具,地圖等),只JSON格式拉從另一個域數據,不要忘記。

我希望這是有益的,感謝您的耐心:-),和平,對不起碼格式,它不能很好地工作

16

您可以使用YQL的要求去做,而不需要舉辦自己的代理。我做了一個簡單的功能,使其更易於運行命令:

function RunYQL(command, callback){ 
    callback_name = "__YQL_callback_"+(new Date()).getTime(); 
    window[callback_name] = callback; 
    a = document.createElement('script'); 
    a.src = "http://query.yahooapis.com/v1/public/yql?q=" 
      +escape(command)+"&format=json&callback="+callback_name; 
    a.type = "text/javascript"; 
    document.getElementsByTagName("head")[0].appendChild(a); 
} 

如果您有jQuery的,你可以使用$ .getJSON代替。

樣品可以是這樣的:

RunYQL('select * from html where url="http://www.google.com/"', 
     function(data){/* actions */} 
); 
1

這裏是你如何能做到這一個簡單的方法,而不必使用任何幻想,甚至是JSON。

首先,創建一個服務器端腳本來處理您的請求。喜歡的東西http://www.example.com/path/handler.php

您將參數調用它,是這樣的:.../handler.php參數1 = 12345 &參數2 = 67890

它裏面,處理收到數據後,輸出

現在
document.serverResponse('..all the data, in any format that suits you..'); 
// Any code could be used instead, because you dont have to encode this data 
// All your output will simply be executed as normal javascript 

,在客戶端腳本,使用以下命令:

document.serverResponse = function(param){ console.log(param) } 

var script = document.createElement('script'); 
script.src='http://www.example.com/path/handler.php?param1=12345&param2=67890'; 
document.head.appendChild(script); 

此方法的唯一限制是您可以發送給服務器的參數的最大長度。但是,您始終可以發送多個請求。

2

如果您使用的是PHP腳本來從遠程服務器的應答,在開始時加入這一行:

header("Access-Control-Allow-Origin: *");