Node.js 在express/nodejs应用程序中为存储在S3中的文件提供服务
我有一个应用程序,其中用户的照片是私人的。我将照片(缩略图)存储在AWS s3中。网站中有一个页面,用户可以在其中查看他的照片(即缩略图)。现在我的问题是如何提供这些文件。我评估过的一些选项包括:Node.js 在express/nodejs应用程序中为存储在S3中的文件提供服务,node.js,nginx,amazon-s3,express,fileserver,Node.js,Nginx,Amazon S3,Express,Fileserver,我有一个应用程序,其中用户的照片是私人的。我将照片(缩略图)存储在AWS s3中。网站中有一个页面,用户可以在其中查看他的照片(即缩略图)。现在我的问题是如何提供这些文件。我评估过的一些选项包括: 使用签名url生成从CloudFront(或AWS)服务文件。但问题是每次用户刷新页面时,我都必须再次创建这么多已签名的URL并加载它。因此,我将无法在浏览器中缓存图像,这将是一个不错的选择。在javascript中还有什么需要做的吗?由于安全问题,我不能拥有这些URL的有效期更长。第二,在这个时间
- 使用签名url生成从CloudFront(或AWS)服务文件。但问题是每次用户刷新页面时,我都必须再次创建这么多已签名的URL并加载它。因此,我将无法在浏览器中缓存图像,这将是一个不错的选择。在javascript中还有什么需要做的吗?由于安全问题,我不能拥有这些URL的有效期更长。第二,在这个时间范围内,如果有人获得了这个url,他就可以查看文件,而无需通过应用程序的身份验证
- 另一个选择是在从S3服务器流式传输文件后,从my express应用程序本身提供文件。这允许我拥有http缓存头,因此启用浏览器缓存。它还确保没有经过身份验证的任何人都无法查看文件。理想情况下,我希望使用NGINX代理将文件和我托管的主机流传输到NGINX的另一端。但正如我所见,只有当文件存在于同一系统的文件中时,这才可能实现。但是在这里,我必须对它进行流式处理,并在流完成后返回。不希望将文件存储在本地
那么,理想的做法是什么呢?关于这些方法的特定问题的答案?如果照片确实需要保密,我会考虑使用CloudFront选项。看起来您在管理自己的安全策略时会有更多的灵活性。我认为nginx的设置可能比需要的更复杂。Express作为一个远程代理,应该可以提供非常好的性能,它使用请求从S3获取项目,并将它们流式传输给授权用户。我强烈建议大家看看Asset Rack,它使用散列签名在浏览器中启用永久缓存。您将无法使用默认机架,因为您需要计算每个文件的MD5(可能是在上载时?),而流式传输时您无法这样做。但是,根据应用程序的不同,浏览器无需重新蚀刻图像,这可以为您节省大量工作。关于第二个选项,您应该能够设置 关于你的第一个选择。您是否考虑过以不同的方式保护您的图像? 在S3中存储图像时,不能使用散列和随机文件名吗?这将是相当直接的文件名难以猜测+这样你就不会有性能问题查看图像回来
这是facebook使用的技术。只要知道URL,您在注销时仍然可以查看图像。我只想从S3流式传输它。这很容易,而签名URL则要困难得多。将图像上载到S3时,只需确保设置了
内容类型
和内容长度
标题
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)
})
})
如果您使用
302将用户重定向到已签名的url,则Found
浏览器将根据其缓存控件
标题缓存生成的图像,并且不会第二次请求它
要防止浏览器缓存已签名的url本身,您应将适当的缓存控制
标题与之一起发送:
Cache-Control: private, no-cache, no-store, must-revalidate
因此,下次它将向原始url发送请求,并将重定向到新的签名url
您可以使用knox
生成签名url
但不要忘记为每个上传的图像设置适当的标题。我建议您同时使用缓存控制
和过期
标题,因为某些浏览器不支持缓存控制
标题,而过期
只允许您设置绝对过期时间
使用第二个选项(通过应用程序传输图像),您可以更好地控制情况。例如,您将能够根据当前日期和时间为每个响应生成Expires
标题
但是速度呢?使用签名URL有两个优点,这可能会影响页面加载速度
首先,您不会使服务器过载。如果生成签名URL很快,因为您只是在散列您的AWS凭据。要在服务器上传输图像,您需要在页面加载期间保持大量额外的连接。无论如何,除非您的服务器是硬加载的,否则不会有任何实际的区别
其次,浏览器在页面加载期间每个主机名只保持两个并行连接。所以,在下载图像和URL时,浏览器将保持并行解析图像和URL。它还可以防止图像下载阻止任何其他资源的下载
无论如何,为了绝对确定您应该运行一些基准测试。我的回答是基于我对HTTP规范的了解和我在web开发方面的经验,但我自己从未尝试过以这种方式提供图像。直接从S3提供具有长缓存生存期的公共映像可以提高页面速度,我相信如果您通过重定向来实现这一点,情况不会改变
您应该记住,通过服务器传输图像将使Amazon CloudFront的所有好处化为乌有。但只要您直接从S3提供内容,这两个选项都可以正常工作
因此,有两种情况下,使用签名URL会加快页面速度:
- 如果你在一个页面上有很多图片
- 如果您使用CloudFront提供图像