简体   繁体   English

使用 aws-sdk 和 Node/Express 将简单的文件上传到 S3

[英]Simple file upload to S3 using aws-sdk and Node/Express

I am at a loss of what I am doing wrong, here is what I have:我不知道我做错了什么,这是我所拥有的:

HTML HTML

<html>
<body>
    <form method="POST" action="/upload" enctype="multipart/form-data">
        <div class="field">
            <label for="image">Image Upload</label>
            <input type="file" name="image" id="image">
        </div>
        <input type="submit" class="btn" value="Save">
    </form>
</body>
</html>

Port 5000 is my Node.js server's port. Port 5000 是我的Node.js服务器的端口。

In this example I am using POST to /upload , and it works fine.在这个例子中,我使用POST/upload ,它工作正常。

module.exports = function(app, models) {

    var fs = require('fs');
    var AWS = require('aws-sdk');
    var accessKeyId =  process.env.AWS_ACCESS_KEY || "xxxxxx";
    var secretAccessKey = process.env.AWS_SECRET_KEY || "+xxxxxx+B+xxxxxxx";

    AWS.config.update({
        accessKeyId: accessKeyId,
        secretAccessKey: secretAccessKey
    });

    var s3 = new AWS.S3();

    app.post('/upload', function(req, res){

        var params = {
            Bucket: 'makersquest',
            Key: 'myKey1234.png',
            Body: "Hello"
        };

        s3.putObject(params, function (perr, pres) {
            if (perr) {
                console.log("Error uploading data: ", perr);
            } else {
                console.log("Successfully uploaded data to myBucket/myKey");
            }
        });
    });

}

Now I want to post the file that I am POST ing, which is where the problem arises.现在,我要发布的文件,我POST ING,这是哪里出了问题就出现了。

module.exports = function(app, models) {

    var fs = require('fs');
    var AWS = require('aws-sdk');
    var accessKeyId =  process.env.AWS_ACCESS_KEY || "xxxxxx";
    var secretAccessKey = process.env.AWS_SECRET_KEY || "+xxxxxx+B+xxxxxxx";

    AWS.config.update({
        accessKeyId: accessKeyId,
        secretAccessKey: secretAccessKey
    });

    var s3 = new AWS.S3();

    app.post('/upload', function(req, res){
        var path = req.files.image.path;
        fs.readFile(path, function(err, file_buffer){
            var params = {
                Bucket: 'makersquest',
                Key: 'myKey1234.png',
                Body: file_buffer
            };

            s3.putObject(params, function (perr, pres) {
                if (perr) {
                    console.log("Error uploading data: ", perr);
                } else {
                    console.log("Successfully uploaded data to myBucket/myKey");
                }
            });
        });
    });
}

The error I get is:我得到的错误是:

TypeError: Cannot read property 'path' of undefined类型错误:无法读取未定义的属性“路径”

As a matter of fact files is completely empty.事实上, files是完全空的。

I am assuming I am missing something pretty obvious but I can't seem to find it.我假设我遗漏了一些很明显的东西,但我似乎找不到它。

You will need something like multer to handle multipart uploading.您将需要诸如multer类的multer来处理分段上传。 Here is an example streaming your file upload to s3 using aws-sdk .这是使用aws-sdk将文件上传到 s3 的示例。

var multer = require('multer');
var AWS = require('aws-sdk');

var accessKeyId =  process.env.AWS_ACCESS_KEY || "xxxxxx";
var secretAccessKey = process.env.AWS_SECRET_KEY || "+xxxxxx+B+xxxxxxx";

AWS.config.update({
    accessKeyId: accessKeyId,
    secretAccessKey: secretAccessKey
});

var s3 = new AWS.S3();

app.use(multer({ // https://github.com/expressjs/multer
  dest: './public/uploads/', 
  limits : { fileSize:100000 },
  rename: function (fieldname, filename) {
    return filename.replace(/\W+/g, '-').toLowerCase();
  },
  onFileUploadData: function (file, data, req, res) {
    // file : { fieldname, originalname, name, encoding, mimetype, path, extension, size, truncated, buffer }
    var params = {
      Bucket: 'makersquest',
      Key: file.name,
      Body: data
    };

    s3.putObject(params, function (perr, pres) {
      if (perr) {
        console.log("Error uploading data: ", perr);
      } else {
        console.log("Successfully uploaded data to myBucket/myKey");
      }
    });
  }
}));

app.post('/upload', function(req, res){
    if(req.files.image !== undefined){ // `image` is the field name from your form
        res.redirect("/uploads"); // success
    }else{
        res.send("error, no file chosen");
    }
});

Latest Answer @ Dec-2016 [New]最新答案 @ 2016 年 12 月[新]

Use multer-s3 for multipart uploading to s3 without saving on local disk as:使用multer-s3分段上传到 s3 而不保存在本地磁盘上:

var express = require('express'),
    aws = require('aws-sdk'),
    bodyParser = require('body-parser'),
    multer = require('multer'),
    multerS3 = require('multer-s3');

aws.config.update({
    secretAccessKey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    accessKeyId: 'XXXXXXXXXXXXXXX',
    region: 'us-east-1'
});

var app = express(),
    s3 = new aws.S3();

app.use(bodyParser.json());

var upload = multer({
    storage: multerS3({
        s3: s3,
        bucket: 'bucket-name',
        key: function (req, file, cb) {
            console.log(file);
            cb(null, file.originalname); //use Date.now() for unique file keys
        }
    })
});

//open in browser to see upload form
app.get('/', function (req, res) {
    res.sendFile(__dirname + '/index.html');
});

//use by upload form
app.post('/upload', upload.array('upl',1), function (req, res, next) {
    res.send("Uploaded!");
});

app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
});

Latest Answer @ Mar-2016 [Old-One]最新答案 @ Mar-2016 [旧一]

Edited 1 use multer@1.1.0 and multer-s3@1.4.1 for following snippet :编辑 1使用multer@1.1.0multer-s3@1.4.1用于以下代码段

var express = require('express'),
    bodyParser = require('body-parser'),
    multer = require('multer'),
    s3 = require('multer-s3');

var app = express();

app.use(bodyParser.json());

var upload = multer({
    storage: s3({
        dirname: '/',
        bucket: 'bucket-name',
        secretAccessKey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
        accessKeyId: 'XXXXXXXXXXXXXXX',
        region: 'us-east-1',
        filename: function (req, file, cb) {
            cb(null, file.originalname); //use Date.now() for unique file keys
        }
    })
});

//open in browser to see upload form
app.get('/', function (req, res) {
    res.sendFile(__dirname + '/index.html');
});

//use by upload form
app.post('/upload', upload.array('upl'), function (req, res, next) {
    res.send("Uploaded!");
});

app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
});

For complete running example clone express_multer_s3 repo and run node app .对于完整的运行示例克隆express_multer_s3 repo并运行node app

Simple S3 File Upload Without Multer无需 Multer 的简单 S3 文件上传

var express = require('express')
const fileUpload = require('express-fileupload');
const app = express();

app.use(fileUpload());


var AWS = require('aws-sdk');

app.post('/imageUpload', async (req, res) => {
    AWS.config.update({
        accessKeyId: "ACCESS-KEY", // Access key ID
        secretAccesskey: "SECRET-ACCESS-KEY", // Secret access key
        region: "us-east-1" //Region
    })


    const s3 = new AWS.S3();

    // Binary data base64
    const fileContent  = Buffer.from(req.files.uploadedFileName.data, 'binary');

    // Setting up S3 upload parameters
    const params = {
        Bucket: 'BUKET-NAME',
        Key: "test.jpg", // File name you want to save as in S3
        Body: fileContent 
    };

    // Uploading files to the bucket
    s3.upload(params, function(err, data) {
        if (err) {
            throw err;
        }
        res.send({
            "response_code": 200,
            "response_message": "Success",
            "response_data": data
        });
    });

})

app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
});

Sounds like you might not have the express bodyParser middleware setup. 听起来你可能没有明确的bodyParser中间件设置。 Can you post your entire server file (app.js, server.js, what have you) 你可以发布你的整个服务器文件(app.js,server.js,你有什么)

您可以尝试使用image / png或任何正确的mime类型,而不是multipart / form-data。

You need something like multer in your set of middleware to handle multipart/form-data for you and populate req.files .您需要在中间件集中使用multer 之类的东西为您处理multipart/form-data并填充req.files From the doco:从文件:

var express = require('express')
var multer  = require('multer')

var app = express()
app.use(multer({ dest: './uploads/'}))

Now req.files.image.path should be populated in your app.post function.现在req.files.image.path应该填充在你的app.post函数中。

It looks like your req.files.image is undefined. 看起来你的req.files.image是未定义的。 console.log out what req.files.image returns and see if you can go from there. console.log退出req.files.image返回的内容,看看你是否可以从那里开始。

This stack overflow was the best answer I found explaining exactly how to get Node to S3 working.这个堆栈溢出是我找到的最好的答案,它解释了如何让 Node 到 S3 工作。

AWS Missing credentials when i try send something to my S3 Bucket (Node.js) 当我尝试向我的 S3 存储桶 (Node.js) 发送内容时,AWS 缺少凭证

This in addition to some more stuff I had to hack on to get it all working.除了一些我必须破解才能让它全部工作的东西之外。 In my situation I was using a MEAN stack application so my Node file I was working with was a route file.在我的情况下,我使用的是 MEAN 堆栈应用程序,因此我使用的 Node 文件是一个路由文件。

my aconfig.json file with the amazon credentials looks like this:我的带有 amazon 凭据的 aconfig.json 文件如下所示:

{ "accessKeyId": "*****YourAccessKey****", "secretAccessKey": "***YourSecretKey****" }

The final contents of the route file look like the file pasted below.路由文件的最终内容类似于下面粘贴的文件。

router.post('/sendToS3', function(req, res) {

var fs = require('fs');
var multer = require('multer');
var AWS = require('aws-sdk');
var path = require('path');

var awsCredFile = path.join(__dirname, '.', 'aconfig.json');

console.log('awsCredFile is');
console.log(awsCredFile);

AWS.config.loadFromPath(awsCredFile);

var s3 = new AWS.S3();

var photoBucket = new AWS.S3({params: {Bucket: 'myGreatBucketName'}});

var sampleFile = {
    "_id" : 345345,
    "fieldname" : "uploads[]",
    "originalname" : "IMG_1030.JPG",
    "encoding" : "7bit",
    "mimetype" : "image/jpeg",
    "destination" : "./public/images/uploads",
    "filename" : "31a66c51883595e74ab7ae5e66fb2ab8",
    "path" : "/images/uploads/31a66c51883595e74ab7ae5e66fb2ab8",
    "size" : 251556,
    "user" : "579fbe61adac4a8a73b6f508"
};

var filePathToSend = path.join(__dirname, '../public', sampleFile.path);


function uploadToS3(filepath, destFileName, callback) {
    photoBucket
        .upload({
            ACL: 'public-read',
            Body: fs.createReadStream(filepath),
            Key: destFileName.toString(),
            ContentType: 'application/octet-stream' // force download if it's accessed as a top location
        })
        // http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3/ManagedUpload.html#httpUploadProgress-event
        .on('httpUploadProgress', function(evt) { console.log(evt); })
        // http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3/ManagedUpload.html#send-property
        .send(callback);
}

multer({limits: {fileSize:10*1024*1024}});

console.log('filePathToSend is ');
console.log(filePathToSend);

uploadToS3(filePathToSend, sampleFile.filename, function (err, data) {
    if (err) {
        console.error(err);
        return res.status(500).send('failed to upload to s3').end();
    }
    res.status(200)
        .send('File uploaded to S3: '
            + data.Location.replace(/</g, '&lt;')
            + '<br/><img src="' + data.Location.replace(/"/g, '&quot;') + '"/>')
        .end();
});

console.log('uploading now...');

});

This took me a while to finally get working, but if you setup the route below, update the sampleFile JSON to point to a real file on your system and hit it with Postman it will publish a file to your S3 account.这花了我一段时间才最终开始工作,但是如果您设置了下面的路线,请更新 sampleFile JSON 以指向您系统上的真实文件,并使用 Postman 命中它,它将向您的 S3 帐户发布一个文件。

Hope this helps希望这可以帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM