一尘不染

在Express / NodeJS应用中提供S3中存储的文件

node.js

我有一个应用,其中用户的照片是私人的。我将照片(也有缩略图)存储在AWS
s3中。网站上有一个页面,用户可以在其中查看他的照片(即缩略图)。现在,我的问题是如何处理这些文件。我评估过的一些选项是:

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

我无法评估这两个选项中的哪一个是更好的选择?我想将尽可能多的工作重定向到S3或Cloudfront,但是即使使用单个URL也会使请求首先到达我的服务器。我也想要缓存功能。

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


阅读 352

收藏
2020-07-07

共1个答案

一尘不染

我只是从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)
  })
})
2020-07-07