是否可以执行异步跨域文件上传?

Šim*_*das 47 html javascript iframe file-upload cross-domain

有可能的!参见下文.


首先,让我使用此图解释如何实现异步文件上传:


抱歉.我关闭了我的一个域名,图像现在已经消失了.这是一个非常好的形象.这是在我发现Stack Overflow允许通过Imgur上传图像之前.


正如您所看到的,诀窍是让HTTP响应加载到隐藏的IFRAME元素而不是页面本身.(这是通过target在使用JavaScript提交FORM时设置FORM元素的属性来完成的.)

这有效.但是,我面临的问题是服务器端脚本位于不同的域上.FORM-submit是一个跨域HTTP请求.现在,服务器端脚本启用了CORS,这使我的网页有权读取从我的页面到该脚本发出的HTTP请求的响应数据 - 但这只有在我通过Ajax接收HTTP响应时才有效, ergo,JavaScript.

但是,在这种情况下,响应指向IFRAME元素.一旦XML响应进入IFRAME,其URL将是删除脚本 - 例如http://remote-domain.com/script.pl.

不幸的是,CORS没有涵盖这种情况(至少我认为) - 我无法读取IFRAME的内容,因为它的URL与页面的URL(不同的域)不匹配.我收到此错误:

不安全的JavaScript尝试使用URL hxxp://my-domain.com/outer.html从具有URL hxxp://remote-domain.com/script.pl的框架访问框架.域,协议和端口必须匹配.

由于IFRAME的内容是一个XML文档,因此IFRAME中没有可以使用的JavaScript代码postMessage.

所以我的问题是:如何从IFRAME获取XML内容?

正如我上面所说,我能够直接检索跨域HTTP响应(启用CORS),但似乎我无法在加载到IFRAME后读取跨域HTTP响应.

好像这个问题不够无法解决,让我排除这些解决方案:

  1. easyXDM和类似技术需要远程域上的端点,

  2. 改变XML响应(包括SCRIPT元素),

  3. 服务器端代理 - 我知道我的域可以有一个服务器端脚本,可以作为代理.

那么,除了这两个解决方案,这可以做到吗?


可以办到!!

事实证明,可以伪造一个模仿multipart/form-dataFORM提交的XHR请求(Ajax请求)(在上面的图像中用于将文件上传到服务器).

诀窍是使用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.com/script.pl', true);
xhr.onreadystatechange = responseHandler;
xhr.send(fd);
Run Code Online (Sandbox Code Playgroud)

上面的方法执行异步文件上传,这相当于上图中描述的常规文件上传,并通过提交此表单实现:

<form action="http://remote-domain.com/script.pl" 
        enctype="multipart/form-data" method="post">
    <input type="file" name="file">
</form>
Run Code Online (Sandbox Code Playgroud)

像一个老板一样 :)

Eli*_*rey 9

只需使用表单中的数据发送跨域XHR请求,而不是提交表单.CORS仅适用于前者.

如果你必须采用另一种方式,请使用postMessage与框架协商.

由于IFRAME的内容是一个XML文档,因此IFRAME中没有可以使用postMessage的JavaScript代码.

那怎么阻止你?在XML或SVG名称空间(<script xmlns="http://www.w3.org/1999/xhtml" type="application/ecmascript" src="..."/>)下的任何位置包含一个脚本元素.

  • 不,可以通过XHR上传`Files`(只是`Blob`).所有当前浏览器和IE10都支持使用W3C文件API http://www.w3.org/TR/FileAPI/上传文件 - 只需执行`xhr.send(file_input.files [0])`. (2认同)