這是可能的!參見下文。
首先,讓我用這個圖來講解如何異步文件上傳可以實現:是否可以執行異步跨域文件上傳?
對不起。我關閉了我的一個域,現在圖像已經消失。這是一個非常好的形象,但。這是在我發現Stack Overflow允許通過Imgur上傳圖像之前。
正如你所看到的,訣竅是讓HTTP響應加載到一個隱藏的IFRAME元素,而不是頁面本身。 (這是通過提交的JavaScript表單時設置表單元素的target
屬性來完成的。)
這工作。但是,我面臨的問題是服務器端腳本位於不同的域。 FORM-submit是一個跨域HTTP請求。現在,服務器端腳本啓用了CORS,這使得我的網頁有權讀取從我的頁面到該腳本的HTTP請求的響應數據 - 但只有在通過Ajax接收HTTP響應時纔有效, ergo,JavaScript。
然而,INT這種情況下,響應指向IFRAME元素。一旦XML響應登陸到IFRAME,它的URL將成爲刪除腳本 - 例如http://remote-domain.com/script.pl
。
不幸的是,CORS不包括這種情況下(至少我認爲) - 我無法讀取IFRAME的內容,因爲它的URL不匹配的頁面(不同領域)的URL。我得到這個錯誤:
Unsafe JavaScript attempt to access frame with URL hxxp://remote-domain.com/script.pl from frame with URL hxxp://my-domain.com/outer.html. Domains, protocols and ports must match.
而且,由於IFRAME的內容是一個XML文檔,有IFRAME這可能使得使用postMessage
或裏面的東西沒有JavaScript代碼。
所以我的問題是:我怎樣才能從IFRAME獲得XML內容是什麼?
正如我上面所說的,我能夠直接檢索跨域HTTP響應(啓用CORS),但似乎一旦它們加載到IFRAME中,我就無法讀取跨域HTTP響應。
而且好像這個問題是不可解決的不夠,讓我排除這些解決方案:
easyXDM並需要在遠程域終點類似的技術,
改變XML響應(包括腳本元素),
服務器端代理 - 我明白,我可以在我的域中的服務器端腳本可以引作爲代理。
因此,除了這兩個解決方案之外,這可以做到嗎?
它可以做到!
事實證明,可以僞造一個模仿multipart/form-data
FORM提交的XHR請求(Ajax請求)(用於上圖將文件上傳到服務器)。
訣竅是使用FormData
的構造函數 - 閱讀this Mozilla Hacks article瞭解更多信息。
這是你如何做到這一點:
// STEP 1
// retrieve a reference to the file
// <input type="file"> elements have a "files" property
var file = input.files[0];
// STEP 2
// create a FormData instance, and append the file to it
var fd = new FormData();
fd.append('file', file);
// STEP 3
// send the FormData instance with the XHR object
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://remote-domain.com/script.pl', true);
xhr.onreadystatechange = responseHandler;
xhr.send(fd);
上述方法執行異步文件uplaod,這等同於由提交此表格上方的圖像中的描述和實現的常規文件上傳:
<form action="http://remote-domain.com/script.pl"
enctype="multipart/form-data" method="post">
<input type="file" name="file">
</form>
如果您無法編輯遠程服務器響應,則不可以。如果您可以編輯上傳網站的來源,則可以使用hashchange或postmessage技巧。 – William
如果您不太在意舊版瀏覽器,那麼您可以使用更新穎的上傳方法,在該方法中,您可以通過JS上傳文件並通過AJAX發佈文件。如果這聽起來像是一個好主意,請讓我知道,我會將其作爲答案發布。 –
@Thomas我不關心舊版瀏覽器 - 事實上,即使它只在一個瀏覽器中工作,我也可以使用':)'。你能再詳細一點嗎?恐怕服務器腳本需要一個'