2013-07-07 49 views
19

我有应用程序,用户的照片是私人的。我在AWS s3中存储照片(缩略图)。用户可以在网站上看到他的照片(即缩略图)。现在我的问题是如何提供这些文件。我已评估的一些选项为:在express/nodejs应用程序中存储在S3中的文件

  • 使用签署的url生成从CloudFront(或AWS)提供文件。但问题是每次用户刷新页面时,我都必须重新创建这么多已签名的URL并加载它。因此,我不能在浏览器中缓存图像,这将是一个不错的选择。无论如何,仍然在JavaScript中做?由于安全问题,我无法长时间保持这些网址的有效性。其次,在这段时间内,如果有人获得了该网址,他可以查看该文件,而无需通过应用程序的身份验证。
  • 其他选项是在从S3服务器进行流式传输之后,从我的快速应用程序本身提供文件。这使我可以拥有http缓存头,因此可以启用浏览器缓存。它还确保没有人可以查看文件,而无需进行身份验证。理想情况下,我想流式传输文件,并使用NGINX代理中继将另一端流式传输到NGINX。但是,正如我所看到的,只有当文件存在于同一个系统文件中时才有可能。但是在这里,我必须流式传输并在流完成时返回。不想在本地存储文件。

我不能评估哪两个选项是更好的选择?我想尽可能多地将工作重定向到S3或cloudfront,但即使使用单个url也会将请求首先发送到我的服务器。我也想要缓存功能。

那么最理想的方法是什么?与这些方法有关的特定问题的答案?

回答

19

我只是从S3流。这很容易,并且签名的URL更加困难。只需确保在将图像上传到S3时设置了content-typecontent-length标题。

var aws = require('knox').createClient({ 
    key: '', 
    secret: '', 
    bucket: '' 
}) 

app.get('/image/:id', function (req, res, next) { 
    if (!req.user.is.authenticated) { 
    var err = new Error() 
    err.status = 403 
    next(err) 
    return 
    } 

    aws.get('/image/' + req.params.id) 
    .on('error', next) 
    .on('response', function (resp) { 
    if (resp.statusCode !== 200) { 
     var err = new Error() 
     err.status = 404 
     next(err) 
     return 
    } 

    res.setHeader('Content-Length', resp.headers['content-length']) 
    res.setHeader('Content-Type', resp.headers['content-type']) 

    // cache-control? 
    // etag? 
    // last-modified? 
    // expires? 

    if (req.fresh) { 
     res.statusCode = 304 
     res.end() 
     return 
    } 

    if (req.method === 'HEAD') { 
     res.statusCode = 200 
     res.end() 
     return 
    } 

    resp.pipe(res) 
    }) 
}) 
+1

我会以你的答案为例。非常感谢。但是,如果你不介意你是否可以再帮助我一件事。使用AWS-SDK更好还是knox? –

+1

从未尝试过aws-sdk。然而,Knox维护者更多地参与节点社区。 –

+1

但是??然而你没有提到什么? –

1

如果照片真的需要保持私密,我会关注使用CloudFront选项。看起来你在管理自己的安全策略方面会有更多的灵活性。我认为nginx设置可能比必要的更复杂。 Express应该可以提供非常好的性能,可以作为远程代理使用,它使用请求从S3获取项目并将其传送给授权用户。我强烈推荐看看Asset Rack,它使用散列签名来启用浏览器中的永久缓存。您将无法使用默认的机架,因为您需要计算每个文件的MD5(可能是上载?),这是流式传输时无法完成的。但取决于您的应用程序,它可以为浏览器从不需要重新获取图像节省大量的工作量。

+0

如果我不流的照片,而等待文件被下载到缓冲区,比给它返回给用户? https://github.com/techpines/asset-rack/blob/master/lib/asset.coffee#L200: –

+1

当您收到文件,使用相同的MD5哈希是资产机架采用指纹识别它。使用knox将文件名上传到S3。然后,当用户请求文件时,请使用everyauth或passport进行身份验证,如果成功,请使用knox从S3获取文件并将其提供给用户,并将缓存控制设置为1年缓存,资产架的使用方式。 – dankohn

+0

是啊...您的想法看起来不错,但为什么我应该knox,而我可以使用AWS-SDK。 –

0

关于第二个选项,您应该可以设置cache control headers directly in S3

关于你的第一个选项。你有没有考虑以不同的方式保护你的图像? 当您在S3中存储图像时,是否可以使用散列且随机的文件名?如果文件名难以猜出,这将是非常直接的方式+这种方式你不会有任何性能问题,查看图像回来。

这是Facebook使用的技巧。只要知道URL,您仍然可以在退出时查看图像。

+0

我不希望任何具有该网址的人都能够查看图片。在S3中直接设置缓存控制标题的另一个问题是,每次用户想要查看时,他都会向应用程序请求,并生成一个url并发送给他,所以基本上缓存控制无关紧要。 –

+0

明白了,我已经发布了另一个选项 –

+0

你在哪里发布了另一个选项?如果你的意思是Facebook技术比我已经让你知道我没有任何人的网址能够查看图像,如果他没有权利。 –

7

如果你重定向用户使用浏览器302 Found将根据其cache-control头缓存所产生的图像标识的URL,并不会要求它的第二次。

为了防止浏览器缓存中标识的URL本身,你应该与它一起发送正确Cache-Control头:

Cache-Control: private, no-cache, no-store, must-revalidate 

因此,下一次它会发送请求到原始地址和将被重定向到一个新的签署的网址。

您可以使用signedUrl method生成带knox的签名url。

但不要忘记为每个上传的图像设置正确的标题。我建议您同时使用Cache-ControlExpires标头,因为某些浏览器不支持Cache-Control标头,并且Expires只允许您设置绝对过期时间。

第二个选项(通过您的应用程序流式传输图像)可以更好地控制情况。例如,您可以根据当前的日期和时间为每个响应生成Expires标题。

但速度怎么样?使用签名的url有两个好处,可能会影响页面加载速度。

首先,你不会超载你的服务器。如果速度很快,则生成已签名的网址,因为您只是对您的AWS凭据进行哈希处理并且通过您的服务器流式传输图像,您需要在页面加载期间保持大量额外的连接。无论如何,除非你的服务器很难加载,否则它不会有任何实际的区别。

其次,浏览器在页面加载期间每个主机名只保留两个并行连接。因此,浏览器将在下载图像时并行解析图像。它还会阻止下载图像,阻止下载任何其他资源。

无论如何,要绝对确定你应该运行一些基准测试。我的回答是基于我对HTTP规范的知识以及我在网络开发方面的经验,但我从来没有试图以我自己的方式提供图像。直接从S3提供长缓存生存期的公共图像可以提高页面速度,如果您通过重定向完成,我相信情况不会改变。

您应该记住,通过您的服务器流式传输图像将带来Amazon CloudFront的所有优势。但只要你直接从S3提供内容,这两个选项都可以正常工作。

因此,有两种情况使用已签署的网址应该加速你的页面时:

  • 如果你有一个单一页面上大量的图片。
  • 如果您使用CloudFront提供图像。

如果你只有在每一页上几张图片,并直接从S3为他们提供服务,你可能不会看到任何差别。

重要更新

我进行了一些测试,发现我错了有关缓存。浏览器确实缓存了他们被重定向到的图片。但它将缓存的图像与它重定向到的网址相关联,而不是与原始网址相关联。因此,当浏览器第二次加载页面时,它会再次从服务器请求图像,而不是从缓存中获取图像。当然,如果服务器使用相同的重定向url进行响应,它会首次响应,浏览器将使用它的缓存,但对于已签名的url,情况并非如此。

我发现,迫使浏览器缓存标识的URL以及接收到的数据解决了这个问题。但我不喜欢缓存无效重定向网址的想法。我的意思是,如果浏览器以某种方式错过了图像,它会尝试使用缓存中的无效签名url再次请求它。所以,我认为这不是一个选择。

如果CloudFront的服务更快的图像,或者如果浏览器限制每个主机并行下载的数量,使用浏览器缓存的优势,通过你的服务器超出管道图像的所有缺点都无所谓。

它看起来像大多数社交网络通过隐藏其真实URL背后的一些私人代理解决了私人图像的问题。因此,他们将所有内容存储在公共服务器上,但没有办法在未经授权的情况下将url链接到私人图像。当然,如果您将在新标签中打开私密图片并将网址发送给您的朋友,他也可以看到图片。所以,如果它不适合你,那么最好使用Jonathan Ong's solution

+0

你确定它会比生成signedUrl并重定向它慢吗?关于你能指定哪些东西,速度较慢? –

+0

@SaranshMohapatra我更新了我的答案。 –

+0

好的,谢谢你的回答。我会以结果为基准并回复你。这样可以对其他人有用。而你的答案是我发现的最具描述性的,所以再次感谢。 –

相关问题