是否有可能执行异步跨域文件上传?是否有可能执行异步跨域文件上传?(Is it possible to

2019-05-13 09:05发布

有可能的! 参见下文。


首先,让我用这张图来解释文件如何上传异步可以实现:


抱歉。 我已经关闭了我的领域之一,现在的图像消失。 这是一个非常良好的形象,虽然。 这是以前我发现堆栈溢出通过Imgur允许上传图片。


正如你所看到的,关键是让HTTP响应加载到一个隐藏的IFRAME元素,而不是页面本身。 (这是通过设置在完成的target提交用JavaScript表单时FORM元素的属性。)

这工作。 不过,我所面临的问题是服务器端脚本是在不同的领域 。 形式提交是跨域HTTP请求。 现在,服务器端脚本CORS启用这给我的网页的权限读取从我的网页到该脚本由HTTP的请求的响应数据 - 但如果我收到通过Ajax的HTTP响应的作品而已, ERGO,JavaScript的。

但是,int该情况下,响应指向IFRAME元素。 而一旦XML响应登陆到IFRAME,它的URL将删除脚本-如http://remote-domain.com/script.pl

不幸的是,CORS不包括这种情况下(至少我认为) - 我无法读取IFRAME的内容,因为它的URL不匹配的页面(不同领域)的URL。 我得到这个错误:

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

而且,由于该IFRAME的内容是一个XML文档,有IFRAME可能利用内部没有任何JavaScript代码postMessage什么的。

所以我的问题是: 我怎样才能从IFRAME XML内容?

正如我前面所说,我可以直接检索跨域的HTTP响应(启用CORS),但似乎我无法一旦装载到一个IFRAME看跨域HTTP的响应。

而且好像这个问题是远远不够的不可解,让我排除这些解决方案

  1. easyXDM以及需要对远程域终点类似的技术,

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

  3. 服务器端代理 - 我明白,我可以在我的域中的服务器端脚本这可以作为一个代理。

因此,除了这两个解决方案,可以这样做?


可以办到!!

事实证明,有可能伪造XHR请求(Ajax的请求),其模仿multipart/form-data FORM提交(其上方的图像中的用于上载的文件到服务器)。

诀窍是使用FormData构造-读这Mozilla的黑客文章以获取更多信息。

这是你如何做到这一点:

// 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>

像一个老板一样 :)

Answer 1:

只需发送与形式,而不是提交表单数据跨域XHR请求。 CORS是只为前者。

如果你必须这样做的其他方式,协商使用postMessage的框架。

而且,由于该IFRAME的内容是一个XML文档,有IFRAME它可以利用的postMessage什么的内部没有任何JavaScript代码。

如何阻止你? 包括HTML或SVG命名空间下一个脚本元素( <script xmlns="http://www.w3.org/1999/xhtml" type="application/ecmascript" src="..."/>中的任何地方XML。



Answer 2:

我认为,它无法与你所描述的方式来完成。 一般来说,如果你有跨域问题,您可以通过JSONP途径解决,但只适用于GET请求。 有了HTML5,你可能会发送二进制与GET请求,但是这只是前途未卜。

  • 一个解决办法是通过进行代理的本地网络服务器的请求,在本地使用远程web服务。 这将导致额外的负载为您的本地网络服务器,所以我可以想像,这是不可行的。 如果文件是小和罕见的,虽然,这将很好地做。

  • 另一个解决方案是你发送的文件后,开始轮询服务器。 你可以沿着令牌发送和查询使用常规JSONP服务器的状态。 这样,你不需要从iframe来阅读。

  • 把整个页面在远程服务器上运行的iframe。 这可能只是移动的问题,但如果XML输出是在一些过程的最后一步是完全可行的。

我敢肯定,你有一个很好的理由,处理服务器是在不同的领域,但如果不是,你就不会有这些问题。 也许,这是值得反思?



Answer 3:

如果可以的话,返回一个HTML页面,而不是XML的。
在该页面,您可以在使用SCRIPT标签的命令: parent.postMessage

如果你必须支持旧的浏览器(<IE8为主),你可以写和读window.name下面的2Mb消息。

这两种技术都可以让你不同域的帧之间传递字符串数据。

另一种方法是使用setInterval会重复调用使用父页远程域JSONP知道的状态。

在任何情况下,你需要从远程域合作获取数据。



Answer 4:

下面的方法是工作在我的设置(火狐3.6):

<!-- hidden target frame -->
<iframe name="load_target" id="load_target" onload="process(this);" src="#" ...>

<!-- get data from iframe after load and process them --> 
<script type="text/javascript">
    function process(iframe) {
       var data = iframe.contentWindow.document.body.innerHTML; 
       // got test data="<xml><a>b</a></xml>"
    }
</script>

它在Chrome工作为好,但它是需要排除父页面加载后第一个onload事件呼叫。 这很容易通过设置其在测试一个“全局”变量来完成process()

加成

该方法与表单一起工作

<form action="URL" method="post" enctype="multipart/form-data" target="load_target">

这是提交URL 。 该URL必须驻留在同一个域中父页面page.html 。 如果从数据REMOTE_URL将被下载,那么URL将是一个PHP proxy.php与内容自身域

<?php echo file_get_contents("REMOTE_URL"); ?>

这是一个简单的办法 - 但是,它可能是由问题的条件(2)排除在外。 我已经添加在这里,使我的回答完毕。

其他的方法,只考虑内部框架,通过讨论Mahemoff和乔治Auberger 。



文章来源: Is it possible to perform an asynchronous cross-domain file-upload?