#可以做到!请往下看。
首先,让我用这张图解释一下如何实现异步文件上传:
抱歉,我关闭了其中一个域名,现在这张图片已经不存在了。不过这是在我发现 Stack Overflow 可以通过 Imgur 上传图片之前的事情。
正如您所看到的,诀窍在于让 HTTP 响应加载到一个隐藏的 IFRAME 元素中,而不是页面本身。(这是通过在提交 FORM 表单时使用 JavaScript 设置 FORM 元素的 target 属性来实现的。)
这是行得通的。然而,我面临的问题是,服务器端脚本在不同的域上。FORM 提交是跨域 HTTP 请求。现在,服务器端脚本已启用 CORS,这使得我的网页有权读取从该脚本到我的页面发送的 HTTP 请求的响应数据——但这仅在我通过 AJAX(即 JavaScript)接收 HTTP 响应时才有效。
然而,在这种情况下,响应是指向 IFRAME 元素的。一旦 XML 响应落入 IFRAME,它的 URL 就会成为远程脚本的 URL,例如:http://remote-domain.example/script.pl
。
不幸的是,CORS 并不涉及这种情况(至少我认为是这样)——我无法读取 IFRAME 的内容,因为它的 URL 不匹配页面的 URL(域名不同)。我会收到以下错误:
Unsafe JavaScript attempt to access frame with URL hxxp://remote-domain.example/script.pl from frame with URL hxxp://example.com/outer.html. Domains, protocols and ports must match.
由于 IFRAME 的内容是一个 XML 文档,因此其中没有 JavaScript 代码可以利用 postMessage
或其他东西。
因此,我的问题是: 我如何从 IFRAME 中获取 XML 内容?
如我所言,我能够直接检索跨域HTTP响应(启用CORS),但似乎在它们加载到IFRAME后无法读取跨域HTTP响应。
如果这个问题还不够难解决,那么就让我排除这些解决方案:
easyXDM和类似技术需要远程域上的终端点。
更改XML响应(以包括SCRIPT元素)。
服务器端代理 - 我明白我可以在我的域上有一个服务器端脚本作为代理。
因此,除了这两个解决方案之外,还能做到吗?
#它是可以做到的!
事实证明,可以伪造XHR请求(Ajax请求),模拟multipart/form-data
表单提交(用于将文件上传到服务器,如上图所示)。
诀窍是使用FormData
构造函数 - 请阅读这篇Mozilla Hacks文章获取更多信息。
方法如下:
// 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.example/script.pl', true);
xhr.onreadystatechange = responseHandler;
xhr.send(fd);
以上方法执行异步文件上传,与上述图像中描述的常规文件上传相同,并通过提交此表单实现:
<form action="http://remote-domain.example/script.pl"
enctype="multipart/form-data" method="post">
<input type="file" name="file">
</form>
#像个老板 :)
:)
。你能详细解释一下吗?我担心服务器脚本需要一个<form enctype="multipart/form-data">
,我不确定是否可以用 JavaScript 创建这样的东西... - Šime VidasFormData
构造函数在 Firefox、Chrome 和 Safari 中实现了,但是 Opera 和 IE 并没有。 - Šime Vidas