13

Please let me know how to retrieve image from s3 with nodejs? Honestly, I could upload an image to s3 with nodejs as follows but the problem is how can I complete to retrieve image from s3?

router.get('/image/:imageId', function (req, res, next) {
    // ????
});

var s3 = new aws.S3({ accessKeyId: config.awsAccessId, secretAccessKey: config.awsAccessKey}); 
var upload = multer({
    storage: multerS3({
        s3: s3,
        bucket: config.bucket,
        key: function (req, file, cb) {
            cb(null, file.originalname);
        }
    })
});

router.post('/upload/:id', upload.array('file', 3), function(req, res, next) {
    res.send('Successfully uploaded ' + req.files.length + ' files!');
});
Arpit Solanki
  • 9,567
  • 3
  • 41
  • 57
PPShein
  • 13,309
  • 42
  • 142
  • 227

7 Answers7

23

I've finally found that,

var params = { Bucket: config.bucket, Key: req.params.imageId };
s3.getObject(params, function(err, data) {
    res.writeHead(200, {'Content-Type': 'image/jpeg'});
    res.write(data.Body, 'binary');
    res.end(null, 'binary');
});
PPShein
  • 13,309
  • 42
  • 142
  • 227
  • but, when i retrieve from server side, how can i do show this image ? – krekto Sep 30 '18 at 04:22
  • 1
    @krekto above code return binary format, then just display it. – PPShein Oct 01 '18 at 04:01
  • realy i don't know how do that, i make src="$scope.data" but not working, ($scope is angularjs to bind data value, data is image in binary format), tell me how can i display in this image in binary on the img tag , tx sir – krekto Oct 05 '18 at 05:18
  • 1
    @krekto I've uploaded source code to git, it's using lambda (nodejs) with reactjs. https://github.com/ppshein/retrieve-image-from-s3-with-nodejs – PPShein Oct 06 '18 at 04:25
  • thank you, i understand you backend code, my app is in AngulaJS on the front, because of this difference I still have no idea how to show the image in the img tag. but thank you. – krekto Oct 06 '18 at 05:00
  • 1
    @krekto you don't need to do anything in AngularJS. Just do like in your file ``. If you want to async, it's different story, means need to change some pieces of codes. – PPShein Oct 06 '18 at 16:21
  • works great, thank you !! now tell one thing please, I want this route to be authenticated, but when I call the direct route in n-src I do not know how to put authentication in the route call, have any idea how to do this? – krekto Oct 06 '18 at 17:59
  • that's NodeJS side. – PPShein Oct 07 '18 at 15:17
3

If you use lambda with API gateway to retrieve images then there will be no need to using security keys with appropriate permissions.
Read an image from the bucket and send it as base64 to directly use it in source of image tag in HTML.

const AWS = require('aws-sdk');
//*/ get reference to S3 client 
var s3 = new AWS.S3();
exports.handler = (event, context, callback) => {
    var params = {
  "Bucket": "bucket-name",
  "Key": "object-name"  
    };
    s3.getObject(params, function(err, data){
       if(err) {
           callback(err, null);
       } else {
           let image = new Buffer(data.Body).toString('base64');
           image = "data:"+data.ContentType+";base64,"+image;
           let response = {
        "statusCode": 200,
        "headers": {
            "Access-Control-Allow-Origin": "*",
            'Content-Type': data.ContentType
        },
        "body":image,
        "isBase64Encoded": true
    };
           callback(null, response);
    }
    });
    
};
2

You're looking for the getObject() method.

Chase
  • 3,009
  • 3
  • 17
  • 23
2

Assuming that you are using aws-sdk then you can use getObject method.

Here is sample code

exports.getObjects = function (req, res) {
    var item = req.body;
    var params = { Bucket: req.params.bucketName, Key: 'keyname'}; // keyname can be a filename
    s3.getObject(params, function (err, data) {
        if (err) {
            return res.send({ "error": err });
        }
        res.send({ data });
    });
}

This link may be helpful to you.

Arpit Solanki
  • 9,567
  • 3
  • 41
  • 57
1

A better and faster approach is piping the stream to response, works on Minio S3 Client but I believe it also works on aws amazon js client.

const Minio = require('minio');

const s3Client = new Minio.Client({
    endPoint: 'ep',
    accessKey: 'ak',
    secretKey: 'sk'
});

router.get('/image/:imageId', (req, res) => {

    const { imageId } = req.params;

    s3Client.getObject('bucket', imageId, (err, stream) => {
        if (err) return res.status(500).send(err);

        const contentType = stream.headers['content-type'];

        contentType && res.setHeader('Content-Type', contentType);

        stream.pipe(res);
    });
});


Kon
  • 525
  • 5
  • 11
0

This is what I use with aws-sdk

const params = { Bucket: "YOUR_BUCKET_NAME", Key: "YOUR_FILENAME"}; 
s3.getObject(params).createReadStream().pipe(res);
fufu
  • 1
0

By using @aws-sdk/client-s3 you can get base64 encoded string as following:

async retrieve(key: string): Promise<string> {
  try {
    const params: PutObjectCommandInput = {
      Key: key,
      Bucket: this.bucketName
    };
    const command = new GetObjectCommand(params);
    const response: GetObjectCommandOutput = await s3Client.send(command);
    return await response.Body?.transformToString('base64') || "";
  } catch (e: any) {
    // handle exception
  }
}

For more info check GetObjectCommand doc

Jumshud
  • 1,385
  • 1
  • 13
  • 19