我正在尝试使用Ruby on Rails 4.2将文件从远程存储服务(不是s3 :-))流式传输到客户端。
我的服务器需要处于中间状态以验证客户端请求,但也需要建立对远程存储服务的请求,因为对该服务的所有请求都需要使用自定义标头参数进行身份验证。这使得不可能做一个简单的redirect_to并让客户端直接下载文件(但是如果这实际上可以使用rails,请告诉我!)。此外,我想保留文件的网址为客户端隐藏。
到目前为止,我正在使用名为ZipLine的gem,但这也无法正常工作,因为它仍会在将远程文件发送到客户端之前对其进行缓冲。因为我正在使用unicorn / nginx,这可能也是由于这两个中的任何一个设置阻止了正确的流式传输。
根据rails doc的说明,我尝试添加
listen 3000, tcp_nopush: false
配置/ unicorn.rb但无济于事。
解决方案可能是在本地缓存远程文件一段时间,然后只提供该文件。这会使一些事情变得更容易,但也会产生新的麻烦,例如保持远程和缓存文件同步,为缓存过期设置正确的触发器等。
总结一下:
1)如何完成上述方案?
2)如果这不是一种智能/高效的做事方式,我应该只缓存远程副本吗?
3)在给定方案中,您的经验/建议是什么?
我遇到了散布在互联网周围的各种解决方案,但没有一个能激发出完整的解决方案。
谢谢!
答案 0 :(得分:1)
我假设第三方存储服务具有HTTP访问权限。如果你考虑使用redirect_to
,我认为该服务还提供了允许每个下载授权的方法。与标头中的唯一键一样,过期并且不会将过期时间作为参数暴露给您的秘密api密钥或HMAC签名URL。
无论如何,大多数云存储服务都提供这种文件访问。我强烈建议让服务流传输文件。您的应用应该只是授权用户并重定向到该服务。 Rails允许您在重定向时添加自定义标头。它在Rails guides中进行了讨论。
10.2.1设置自定义标题
如果要为响应设置自定义标头,请选择response.headers 是去做的地方。 headers属性是映射的哈希 标题名称为其值,Rails将设置其中的一些 自动。如果要添加或更改标题,只需指定它即可 到
response.headers
所以你的行动代码最终会是这样的:
def download
# do_auth_check
response.headers["Your-API-Auth-Key"] = "SOME-RANDOM-STRING"
redirect_to url
end
不要通过流式传输所有这些下载来消耗不必要的服务器资源。毕竟我们正在支付云服务:)