Amazon S3 透過 Iframe 上傳
Amazon S3 upload via Iframes
>叹息,我们又回到了这个。我可以轻松地在任何足够好的浏览器上使用 CORS,直接将文件上传到我的 AWS S3 存储桶。但是(它即将到来),对于IE,我必须回到Iframes。简单,设置隐藏的Iframe,创建一个表单,将其目标设置为Iframe名称/id,提交表单。如果上传成功,Iframe 将重定向到我指定的 url,我可以访问我需要的任何内容。但是,如果发生错误,由于 Iframe 现在位于 AWS 域上,我将无法访问错误的 XML 内容。事实上,我什至不知道发生了错误。
我在互联网上看到勇敢的人谈论托管一个html文件,在要上传到的文件的同一存储桶上,然后使用postMessages来路由Iframe内容,或类似的东西。
有人可以向我解释如何实现这个神话般的解决方案吗?Blueimp的jQuery文件上传器似乎解决了这个问题,但是上帝的代码是如此jQuery化,以至于我无法获得它的要点。
为清晰起见进行编辑
- IE<10 没有 FileReader API。
- 由于 1,我无法使用 XDomainRequest 将文件发送到 S3
- 因此,请使用 Iframe 并将其与完整表单一起发布到 S3
- 如果成功,AWS 将重定向到服务器上的页面,该页面将读取标头和
然后返回一个 JSONP 样式的响应,该响应可由客户端上的脚本读取(重定向页面可以
由我指定)。 - 如果出现错误,我现在所能做的就是等待超时到期,然后等待控制台日志
一个 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 的关系:
触发文件上传时,将调用
send()
函数。此函数:创建隐藏的表单元素
使用
src="javascript:false;"
创建 iframe 元素,并将load
事件处理程序绑定到 iframe将 iframe 追加到隐藏表单,并将隐藏表单追加到文档中。
创建 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。
原始表单中的文件输入字段将移动到隐藏表单中,克隆的字段保留在原始字段的位置
提交隐藏表单
将文件输入字段移回原始表单,替换克隆的字段
文件将上传到 S3。如果成功,亚马逊会将 iframe 重定向到
success_action_redirect
URL。如果不成功,亚马逊会返回一个错误,该错误也会加载到 iframe 中。调用 iframe 的
load
事件处理程序。处理程序:尝试保存对 iframe 的
document
对象的引用。如果文件上传失败,处理程序将改为保存undefined
。使用成功代码和对 iframe 的
document
对象(或undefined
)的引用调用完整的回调删除隐藏的表单(和 iframe)
在将控制权返回到代码之前,iframe 的
document
对象将传递到转换器(位于 Iframe 传输插件的底部),具体取决于预期的数据类型。转换器从document
对象中提取该数据,并将其返回(如果文件上传失败,则undefined
)到回调。调用传递给 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 消失。
- 在 TopFrame 上,我们使用 jQuery File Upload 将文件上传到 S3。我们现在要确保它已上传,否则会收到错误。
- TopFrame使用 #postMessage 向XDMFrame发送跨域消息,提供TransportFrame的名称。这条消息实际上是说:"嘿,检查iframe X的内容",当你把它们发回给我时。
- 然后,XDMFrame执行类似
top.frames['iframe X'].document.documentElement
的操作来访问TransportFrame的内容,将它们串化并通过 #postMessage 将它们发送回TopFrame。 - 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将被永久设置为错误检查,这将验证是否发生了错误。
- 如何在Facebook上的iframe应用程序中使后退按钮返回到上一页
- 如何使用JS/jQuery在另一个网站上显示iframe中的特定内容
- X-Frame-Options SAMEORIGIN在我的域上阻止iframe
- 从同一域上的 iframe 中的元素获取值
- 更改网站上所有 iFrame 的 iFrame 尺寸
- 在移动应用程序上滚动iframe会在某个时刻跳到页面顶部
- 在页面上设置iframe
- 从父窗口上的iFrame内容中关闭iFrame
- 将事件发送到其他域上的iFrame
- 如何在我的幻灯片上设置iframe视频
- 如何在 ajax 调用上的 iframe 中加载部分视图
- 移动设备上的 iFrame 重定向主页问题
- 将 PHP 联系表单加载到位于单独 HTML 页面上的 Iframe 中
- j查询对完全加载帧上的 iframe 内部帧的访问
- 在 Chrome.tabs.onUpdate 侦听器上插入 iframe
- 将鼠标悬停在位于我的页面上的 iframe 上的绑定事件,其中包含包含的 src
- 从 iFrame 中每个页面上的 iFrame URL 获取数据
- 如何从不同域上的 iFrame 关闭花式盒子(灯箱)
- 表单定位到不同页面上的 iFrame
- Amazon S3 透過 Iframe 上傳