从Amazon S3通过NodeJS服务器传递文件而不暴露S3 URL?

Aro*_*ron 6 amazon-s3 mongodb amazon-web-services node.js express

我正在尝试将S3文件存储集成到我的NodeJS应用程序中.本教程解释了如何直接上传到S3非常好,但它不适合我的需要,因为我希望只能通过我的网络应用程序的API访问这些文件.我不希望文件在他们的S3网址上公开,我只是希望它们可以通过例如/api/files/<user_id>/<item_id>/<filename>.

我希望下载通过我的API的原因是我可以检查是否允许用户查看此特定文件.

我希望上传通过我的服务器的原因是我知道<item_id>分配文件名,因为这将与其MongoDB _id属性相同.如果我_id在第一个项目有Mongo之前将文件上传到S3,我就无法做到这一点.

我看过但是找不到一个简单的教程,如何通过我的NodeJS应用程序将文件从S3传输到客户端,反之亦然.

谢谢

chr*_*etd 12

快速中间件(用于检查发出请求的用户的授权)和Node AWS SDK的使用的组合应该可以解决问题.

这是一个使用multer进行上传的完整示例.

var express = require('express');
var app = express();
var router = express.Router();
var multer = require('multer');
var upload = multer({
  dest: "tmp/"
});
var fs = require('fs');
var async = require('async');
var AWS = require('aws-sdk');
// Configure AWS SDK here
var s3 = new AWS.s3({
  params: {
    Bucket: 'xxx'
  }
});

/**
 * Authentication middleware
 *
 * It will be called for any routes starting with /files
 */
app.use("/files", function (req, res, next) {
  var authorized = true; // use custom logic here
  if (!authorized) {
    return res.status(403).end("not authorized");
  }
  next();
});

// Route for the upload
app.post("/files/upload", upload.single("form-field-name"), function (req, res) {
  var fileInfo = console.log(req.file);
  var fileStream = fs.readFileSync(fileInfo.path);
  var options = {
    Bucket: 'xxx',
    Key: 'yyy/'+fileName,
    Body: fileStream
  };

  s3.upload(options, function (err) {
    // Remove the temporary file
    fs.removeFileSync("tmp/"+fileInfo.path); // ideally use the async version
    if (err) {
      return res.status(500).end("Upload to s3 failed");
    }
    res.status(200).end("File uploaded");
  });
});

// Route for the download
app.get("/files/download/:name", function (req, res) {
  var fileName = req.params.name;
  if (!fileName) {
    return res.status(400).end("missing file name");
  }
  var options = {
    Bucket: 'xxx',
    Key: 'yyy/'+fileName
  };
  res.attachment(fileName);
  s3.getObject(options).createReadStream().pipe(res);
});

app.listen(3000);
Run Code Online (Sandbox Code Playgroud)

显然,这只是部分测试,缺乏正确的错误处理 - 但希望它能让你大致了解如何实现它.


Gui*_*ume 5

您可以使用S3 REST API。它将允许您直接从后端发出签名请求以 GET 或 PUT 存储桶的对象。

原理与您的链接中描述的原理类似。您的后端需要使用AWS JS 开发工具包来创建签名 URL 来操作对象。您可以在 Express 路由中从 S3 请求某些内容之前或之后进行任何您想要的检查。

这是一个简单的 GET 示例(它的功能并不完整,只是主要思想):

...
[assume that you are in an express route with req/res objects]
...
var aws = require('aws-sdk'),
  s3 = new aws.S3();

aws.config.region = 'your_region';
aws.config.credentials = {
  accessKeyId: 'your_key',
  secretAccessKey: 'your_secret'
};

s3.getSignedUrl('getObject', {Bucket: 'your_bucket', Key: 'your_file_name', Expires: 3600}, function (error, url) {
  if (error || !url) {
    //error while creating the URL
    res.status(500).end();
  } else {
    //make a request to the signed URL to get the file and pipe the res to the client
    request({
      url: url
    }).pipe(res);
  }
});
Run Code Online (Sandbox Code Playgroud)

您将在此处找到更多来自亚马逊的示例。