【问题标题】:What is the best way to upload files to another domain from a browser? [closed]从浏览器将文件上传到另一个域的最佳方法是什么? [关闭]
【发布时间】:2012-04-22 12:42:56
【问题描述】:

我正在为某个社交网络创建预定帖子的网络服务。
需要帮助处理高流量下的文件上传。

流程概览:

  • 用户将文件上传到 SomeServer(不是我的)。
  • SomeServer 然后以 JSON 字符串响应。
  • 我的网络应用应该存储 JSON 响应。

选项 1:保存、cURL POST、删除 tmp
stupid 我让它工作的方式:

  1. 用户将文件上传到 MyWebApp;
  2. MyWebApp cURL 将文件进一步发送到 SomeServer,获取响应。

选项 2:JS 魔法
完美的智能方式:

  1. 用户从 iFrame 中将文件直接上传到 SomeServer;
  2. MyWebApp 通过 JavaScript 获取响应。

但这(?)由于“同源政策”是不可能的,不是吗?

选项 3:nginx 代理?
生产服务器的更好方法:

  1. 用户将文件上传到 MyWebApp;
  2. nginx拦截文件上传,直接发送到SomeServer;
  3. JSON 响应也会被 nginx 截获并由 MyWebApp 处理。

这有什么意义吗?例如,/fileupload Location 的 nginx 配置是什么,以将其代理到 SomeServer?

【问题讨论】:

  • 您可以克服同源策略,但要做到这一点,SomeServer 应在其响应中添加 Cross-Origin Resource Sharing (CORS) 标头。检查它是否实现了 CORS,或者您是否可以说服 SomeServer 的开发人员实现它。
  • SomeServer 确实实现了 CORS 标头,但不幸的是,仅针对它们自己的根域。 “Access-Control-Allow-Origin”HTTP 标头提供单个值。我怀疑他们的开发人员会为我的服务进行调整。所以,回到 nginx/post 转发。
  • 你也可以使用postMessage 在不同源域的框架之间进行通信
  • @tkone 确实如此,但您无法使用postMessage 上传文件。好吧,也许您可​​以以某种方式序列化/反序列化文件。但无论如何,使用postMessage 需要在SomeServer 方面进行开发,而@SergikS 似乎无法做到这一点。顺便说一句,postMessage 被用作 EasyXDM 中通信方式的一部分,我在下面的回答中提到了。
  • @tkone: postMessage 需要服务器端编程。但是你怎么能用 postMessage 上传文件!!

标签: file-upload nginx cross-domain same-origin-policy vk


【解决方案1】:

我只能看到解决此问题的两种主要方法:服务器端代理和 javascript/客户端跨站点上传。你的方法13 是一回事。您是否使用 cURL 或 nginx 发布文件并不重要 - 无论如何都不是性能方面的。因此,如果您已经从您的问题中实施了方法1,我认为没有任何理由切换到3

关于 javascript 和同源策略,似乎有很多方法可以实现您的目标,但在所有这些方法中,您的方案必须得到 SomeServer 的开发人员的支持,或者您必须具有某种访问权限某服务器。以下是可能的大致列表:

  • CORS——必须允许您的域访问 SomeServer 的域;
  • Changing document.domain——这要求您的页面和目标页面托管在同一域的子域上;
  • 使用 Flash 上传器(例如 SWFUpload)——仍然需要通过跨域策略允许您的域,如果是 Flash,则通过 SomeServer 域的根目录中的 crossdomain.xml
  • xdcomm(例如EasyXDM)——要求您至少可以将一个html页面上传到目标域。然后,此页面可用作您使用 SomeServer 的 iframe 操作的 javascript 代理。

实际上,最后一个可能对您来说是真正的可能性,因为您可以将文件上传到 SomeServer。但是,当然,这取决于它是如何实现的——例如,如果有另一个域提供文件,或者如果有一些安全措施不允许您托管 html 文件,它可能无法正常工作。

【讨论】:

  • SomeServer 是 vk,如果这更有意义的话。对于文件上传,他们首先提供可用的 CDN 服务器 url,然后您将文件上传到该 url。它只接受图像/音频/视频,不接受 html/js 或任何东西。所以我会回滚到最初配置 nginx 的问题。绕过 php/tmp 存储/curl 将节省大量的服务器资源,至少使用 curl 内存/php 线程。所以我仍在研究这种方法。
  • 我的印象是您的 Web 应用程序是主要应用程序,并且您在 iframe 中加载了 SomeServer。但是VK允许吗?您能否添加更多关于您的应用是什么(独立网站?VK iframe 应用?)以及它如何使用 VK 的详细信息?
  • 这远远超出了最初问题的范围。 @Shedal,您可以通过 Skype 联系我或给我发电子邮件讨论应用程序本身。关于 nginx 代理文件上传的问题仍然悬而未决。
  • @Serg 我只是认为“JS 魔法”在某些情况下可能并非完全没有问题,具体取决于您的应用程序的设置方式。关于 nginx 代理 - 您是否尝试过使用 HttpProxyModule?例如。如this answer中所述。
  • 感谢其他答案链接。似乎转发 POST 数据违反了 HTTP 规范。也许我应该坚持最初的中间人策略:将用户上传保存在 MyWebApp 上,然后将其进一步 curl 到 SomeServer。
【解决方案2】:

我没有服务器可以用来代替 SomeServer 来测试我的建议,但无论如何我都会试一试。如果我错了,那我猜你只需要use Flash (sample code from VK)

如何使用 iFrame 将文件上传到 SomeServer,接收 JSON 响应,然后使用 postMessage 将 JSON 响应从 iFrame 传递到您网站的主窗口。据我了解,这几乎就是最初创建postMessage 的动机。

总的来说,我正在考虑 like thisYUI's io() module 但添加了 postMessage 以绕过相同的来源政策。

或者在 VK 的情况下,using their explicit iFrame support。在我看来,您可以向全局 VK 对象添加一个方法,然后使用 VK.callMethod() 从 VK 源域调用该方法。您可以使用该解决方法创建一个可以从隐藏 iFrame 读取响应的函数。

所以你使用 VK.api('photos.getUploadServer', ...) 来获取 POST URL。

然后您使用 JS 插入该 URL 作为您用于上传文件的 FORM 的操作。按照io() docscomplete 函数中“以HTML 表单上传文件”下的示例,使用postMessage 将JSON 发送回您的父窗口。见example and docs here。 (如果它不适用于io(),如果我对VK.callMethod() 的看法是正确的,您当然可以使用roll-your-own 示例代码使其工作。)

然后响应postMessage,您可以使用常规AJAX 将JSON 响应上传回您的服务器。

【讨论】:

  • SomeServer 的 url 每次都是新的——从大型 CDN 中挑选。文件上传由 3 个步骤组成: 1) api 调用 api.SomeServer 会返回一个类似 cdn1234.SomeServer 的 url 以及一些参数; 2) 使用包含图片文件数据的字段file1 到该url 的HTTP POST;服务器只返回一个带有哈希字段的 JSON 字符串,我需要进一步。 3) 另一个 api 调用通过其哈希“启用”上传的图片。
  • 我见过的一个非常糟糕的解决方案是将 JS 注入到返回的答案中,而不使用自定义浏览器插件(Chrome 浏览器插件),我的网络应用程序的每个用户都必须安装该插件。然后,该插件会将我的 JS 附加到 SomeServer 域的每个页面,从而实现跨源通信。但这是一个非常奇怪的解决方案。
  • @Serg,你说 SomeServer 实际上是 VK。你读过VK's iFrame documentation吗?特别是在底部,在 IFrame 应用程序中使用 VK API
  • @OldPro 适用于应用程序托管在 VK 内的 iFrame 中的情况。我推测 Serg 的设置正好相反。关于postMessage,我相信只有在 SomeServer 上托管 html/js 代理才有可能。
  • @OldPro 我确实读过。调用 api 方法不是这里的问题。它是通过 POST 请求上传的文件,以及对它的 JSON 响应——托管在单独域上的 myWebApp 希望接收这些响应。这是一个三方难题:U 上传到 AB 想知道 A 响应。无法调整 A 的内部结构。需要在没有浏览器黑客攻击且无法访问其中一台服务器的情况下覆盖同源策略。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-17
  • 2021-06-28
相关资源
最近更新 更多