【发布时间】:2011-10-06 19:33:14
【问题描述】:
有可能!请阅读下文。
首先我用这张图来说明异步文件上传是如何实现的:
对不起。我已经关闭了我的一个域,并且图像现在消失了。这是一个非常好的图像。这是在我发现 Stack Overflow 可以通过 Imgur 上传图片之前。
如您所见,诀窍是让 HTTP 响应加载到隐藏的 IFRAME 元素中,而不是页面本身。 (这是通过在使用 JavaScript 提交 FORM 时设置 FORM 元素的 target 属性来完成的。)
这行得通。但是,我面临的问题是服务器端脚本位于不同的域。 FORM-submit 是一个跨域 HTTP 请求。现在,服务器端脚本启用了 CORS,这使我的网页有权读取从我的页面向该脚本发出的 HTTP 请求的响应数据 - 但只有当我通过 Ajax 接收 HTTP 响应时才有效,因此,JavaScript。
但是,在这种情况下,响应指向 IFRAME 元素。一旦 XML 响应到达 IFRAME,它的 URL 将是删除脚本 - 例如http://remote-domain.com/script.pl.
不幸的是,CORS 没有涵盖这种情况(至少我认为) - 我无法读取 IFRAME 的内容,因为它的 URL 与页面的 URL 不匹配(不同的域)。我收到此错误:
不安全的 JavaScript 尝试使用 URL 访问框架 hxxp://remote-domain.com/script.pl 来自带有 URL 的框架 hxxp://my-domain.com/outer.html。域、协议和端口必须 匹配。
由于 IFRAME 的内容是 XML 文档,因此 IFRAME 中没有 JavaScript 代码可以使用postMessage 或其他东西。
所以我的问题是:如何从 IFRAME 获取 XML 内容?
如上所述,我可以直接检索跨域 HTTP 响应(启用 CORS),但是一旦跨域 HTTP 响应加载到 IFRAME 中,我似乎无法读取它们。
好像这个问题还不够无解,让我排除这些解决方案:
easyXDM 和需要远程域上的端点的类似技术,
更改 XML 响应(以包含 SCRIPT 元素),
服务器端代理 - 我知道我的域上可以有一个服务器端脚本,可以用作代理。
那么,除了这两种解决方案,还能做到吗?
可以的!!
事实证明,可以伪造一个模仿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);
上述方法执行异步文件上传,相当于上图描述的常规文件上传,通过提交这个表单来实现:
<form action="http://remote-domain.com/script.pl"
enctype="multipart/form-data" method="post">
<input type="file" name="file">
</form>
像老板一样:)
【问题讨论】:
-
如果你不能编辑远程服务器的响应,那就不行。如果您可以编辑上传网站的来源,则可以使用 hashchange 或 postmessage 技巧。
-
如果您不太关心旧版浏览器,您可以使用更现代的上传方法,通过 JS 上传文件并通过 AJAX 发布。如果这听起来是个好主意,请告诉我,我会将其作为答案发布。
-
@Thomas 我不关心旧的浏览器——事实上我很好,即使它只在一个浏览器中工作
:)。你能详细说明一下吗?恐怕服务器脚本需要<form enctype="multipart/form-data">,我不确定我是否可以用 JavaScript 创建这样的东西...... -
@Šime,编辑的解决方案是否适用于所有主流浏览器?我可以偶尔使用 AJAX 文件上传。
-
@George 不,很遗憾没有。
FormData构造函数在 Firefox、Chrome 和 Safari 中实现,但在 Opera 和 IE 中没有实现。
标签: javascript html iframe file-upload cross-domain