Amazon S3 透過 Iframe 上傳

Amazon S3 upload via Iframes

本文关键字:上傳 Iframe 透過 S3 Amazon      更新时间:2023-09-26

>叹息,我们又回到了这个。我可以轻松地在任何足够好的浏览器上使用 CORS,直接将文件上传到我的 AWS S3 存储桶。但是(它即将到来),对于IE,我必须回到Iframes。简单,设置隐藏的Iframe,创建一个表单,将其目标设置为Iframe名称/id,提交表单。如果上传成功,Iframe 将重定向到我指定的 url,我可以访问我需要的任何内容。但是,如果发生错误,由于 Iframe 现在位于 AWS 域上,我将无法访问错误的 XML 内容。事实上,我什至不知道发生了错误。

我在互联网上看到勇敢的人谈论托管一个html文件,在要上传到的文件的同一存储桶上,然后使用postMessages来路由Iframe内容,或类似的东西。

有人可以向我解释如何实现这个神话般的解决方案吗?Blueimp的jQuery文件上传器似乎解决了这个问题,但是上帝的代码是如此jQuery化,以至于我无法获得它的要点。

为清晰起见进行编辑

  1. IE<10 没有 FileReader API。
  2. 由于 1,我无法使用 XDomainRequest 将文件发送到 S3
  3. 因此,请使用 Iframe 并将其与完整表单一起发布到 S3
  4. 如果成功,AWS 将重定向到服务器上的页面,该页面将读取标头和
    然后返回一个 JSONP 样式的响应,该响应可由客户端上的脚本读取(重定向页面可以
    由我指定)。
  5. 如果出现错误,我现在所能做的就是等待超时到期,然后等待控制台日志
    一个 IFRAME ID,并弹出一个警报,以便用户可以按 ID 查询 iframe,
    阅读该死的XML内容,找出AWS指定的错误,然后重试(我在讽刺..)
几乎所有

你需要知道的关于jQuery文件上传插件如何进行iframe上传的信息都在它的Iframe Transport插件中(以及支持的结果.html页面)。

作为介绍,您可能需要在他们的跨域上传 wiki 页面上阅读他们的用户说明,特别是跨站点 iframe 传输上传部分。(请注意,根据他们的浏览器支持页面,IE <10 不支持上传进度等细节,因此我认为使用 iframe 传输不会使用这些细节,至少没有付出很大的努力。

(另外,我不相信任何使用文件上传插件的 S3 上传实现都可以访问文件上传错误的 XML 内容)

Iframe 传输插件为 jQuery 添加了一个新的 Ajax "transport" 方法,并且不特定于文件上传插件。您可能需要阅读 jQuery.ajaxTransport() 的文档,以了解 jQuery 提供的用于添加新传输的 API。


我将尝试总结 Iframe 传输插件正在做什么,以及它与将文件上传到 Amazon S3 的关系:

  1. 触发文件上传时,将调用send()函数。此函数:

    • 创建隐藏的表单元素

    • 使用 src="javascript:false;" 创建 iframe 元素,并将load事件处理程序绑定到 iframe

    • 将 iframe 追加到隐藏表单,并将隐藏表单追加到文档中。

  2. 创建 iframe 并加载其"页面"时,将调用其load事件处理程序。处理程序:

    • 从 iframe 中清除自身,并绑定另一个load事件处理程序

    • 配置隐藏表单:

      • 表单的action将是 S3 存储桶的 URL

      • 表单的target设置为 iframe,以便服务器响应加载到 iframe 中

      • 其他领域,例如 AWSAccessKeyId ,被添加。具体来说,success_action_redirect设置为结果的 URL.html在您的服务器上,例如 http://example.org/result.html?%s .

        通常,%s 令牌应替换为服务器端代码的上传结果,但使用 S3,可以通过您的代码使用成功值对其进行硬编码,因为仅当上传成功时,Amazon 才会重定向到此 URL。

      • 原始
      • 表单中的文件输入字段将移动到隐藏表单中,克隆的字段保留在原始字段的位置

    • 提交隐藏表单

    • 将文件输入字段移回原始表单,替换克隆的字段

  3. 文件将上传到 S3。如果成功,亚马逊会将 iframe 重定向到success_action_redirect URL。如果不成功,亚马逊会返回一个错误,该错误也会加载到 iframe 中。

  4. 调用 iframe 的 load 事件处理程序。处理程序:

    • 尝试保存对 iframe 的 document 对象的引用。如果文件上传失败,处理程序将改为保存undefined

    • 使用成功代码和对 iframe 的 document 对象(或undefined)的引用调用完整的回调

    • 删除隐藏的表单(和 iframe)

  5. 在将控制权返回到代码之前,iframe 的 document 对象将传递到转换器(位于 Iframe 传输插件的底部),具体取决于预期的数据类型。转换器从document对象中提取该数据,并将其返回(如果文件上传失败,则undefined)到回调。

  6. 调用传递给 jQuery.ajax()的回调(success 和/或complete)。插件始终返回成功代码,因此不会触发任何error回调。

    如果传递给回调的数据是包含在success_action_redirect中的值,则文件上传成功。如果数据undefined,则文件上传失败。


更新:如果错误 XML 页面与 S3 存储桶位于同一源上,则加载到另一个 iframe 中的 S3 存储桶中的另一个页面可以访问原始 iframe 的内容(因为它们来自同一源)。您的主页可以使用postMessage()(如果您需要支持IE6/7,则为easyXDM的FlashTransport)与第二个iframe进行通信。

这个问题,即使用没有FileReader或FormData支持的浏览器向用户提供准确的反馈,一直困扰着我。我花了整整 3 天的时间试图提出一个解决方案,最终想出了一些几乎一无所有的东西。

让我们深入了解事实:

  • 浏览器IE8/9//成为任何其他不支持文件阅读器的浏览器的可能性很小
  • 上传行为:出于UX原因,我们需要它是"Ajax"
  • 工具带:j查询文件上传*

好的,那么除了使用 iframe 之外,没有其他上传文件的方法。右?

因此,使用jQuery Iframe Transport的jQuery File Upload正如@jeferry_to所描述的那样,是完成这项工作的工具。

*实际上工具/插件不会改变任何事情。

现在怎么办?

井。。。我们需要访问传输 iframe 中的 S3 响应。但我们不能,因为它在不同的域上。因此,我们决定使用涉及第二个iframe的技巧来处理它。

设置:

  • TopFrame,我们的页面(www.myhost.com)
  • iframe TransportFrame (s3.amazonaws.com),由插件自动创建 - 包含 S3 响应
  • iframe XDMFrame(s3.amazonaws.com),在订购时访问TransportFrame,获取响应并将其交付给TopFrame。

场景:

首先,我们需要修改 jQuery Iframe 传输,使其不会自动删除自动生成的表单和传输帧。我们需要这样做,#postMessage 稍后将使用的本质上是异步的,我们不希望在我们尝试访问它时 iframe 消失。

  1. 在 TopFrame 上,我们使用 jQuery File Upload 将文件上传到 S3。我们现在要确保它已上传,否则会收到错误。
  2. TopFrame使用 #postMessage 向XDMFrame发送跨域消息,提供TransportFrame的名称。这条消息实际上是说:"嘿,检查iframe X的内容",当你把它们发回给我时。
  3. 然后,XDMFrame执行类似top.frames['iframe X'].document.documentElement的操作来访问TransportFrame的内容,将它们串化并通过 #postMessage 将它们发送回TopFrame。
  4. TopFrame 接收消息,向用户显示正确的反馈,并删除由于我们的 jQuery Iframe 传输修改而留下的表单和 iframe。

好的,现在一切都应该可以工作了,因为一切都是由书完成的。

不,你甚至不应该打扰。

你看。。。如果您强制现代浏览器使用 iframe 传输而不是 XHR2,上述解决方案确实会像魅力一样工作。

然而,这是毫无意义的。我们希望它在IE8 + 9中工作。

井。。。在IE8/9中,它有时有效,有时无效。通常不会。

为什么?由于IE友好的HTTP错误消息。哦,是的,你读得很好。

如果出现错误,S3 会根据错误(400、403 等)使用 HTTP 错误状态进行响应。现在,根据此处所示的状态和响应长度,IE 会丢弃 S3 响应并将其替换为友好的错误消息。为了克服这个问题,您必须确保响应始终> 512 字节。在这种情况下,你不能保证这样的事情,因为你无法控制响应。S3 确实如此,典型错误小于 512 字节。

总之:

iframe 技巧适用于那些不需要它的浏览器,不适用于那些需要它的浏览器。

不幸的是,我想不出其他任何事情,所以这个案子现在对我来说已经结束了。

在评论中总结我的回答:IE具有CORS支持,但有一些限制:http://www.html5rocks.com/en/tutorials/cors/

这种直接上传到 S3 的实现看起来比 jquery fileupload 简单得多,而且它不在 jQuery 中:http://codeartists.com/post/36892733572/how-to-directly-upload-files-to-amazon-s3-from-your

希望这有帮助!

至于"postMessage"场景,也许iframe应该包含一个简单的javascript

[编辑] 对于被错误消息接管的 iframe

内嵌框架脚本

window.document.onload = function(e){ 
    window.parent.postMessage(document, '*'); //replace '*' with your parent if possible   
}
// just to get the proper document for the parent to target me
window.addEventListener('message',function(e) {
    if (e.domain == 'example.com') { // the domain of your parent frame
        if (e.data == "Salute") {
            window.parent.postMessage("I'm here", '*'); //replace '*' with your parent too
        }
    }
});

现在,家长非常了解iFrame,并且可以跟踪它的状态(取决于它是否在回答简单的postMessage)

父脚本

var iFrameTarget;
var iFrameTakenOver = false;
var timer;
window.addEventListener('message',function(e) {
    if (e.domain == 'example.com') { // the domain of your iframe
        if (e.data) { // e.data contains the iframe document
            if(typeof(e.data) =='object')
                iFrameTarget = e.source;
            elseif(e.data == "I'm here")
            {
                iFrameTakenOver = false;
            }
            timer =setInterval(call_iFrame(),5000); // check iFrame presence in 5 seconds
        }
    }
});
function call_iFrame() {
    iFrameTarget.postMessage('Salute');
    iFrameTakenOver = true;
}

如果iframe没有响应它的"代码"iFrameTakeOver将被永久设置为错误检查,这将验证是否发生了错误。