node.jsamazon-web-servicesexpressamazon-s3pre-signed-url

Accessing AWS S3 Signed URL via Node js Express


I am trying to access the AWS S3 signed URL using a wrapper API created in Node JS and Express.

I am redirecting an url to call the Node API using nginx. In Node API I am setting the 'Content-Type' response headers according to the file type being returned by S3 URL before returning the repsonse from Node API.

When I access the URL to fetch the document in S3 via wrapper Node API I am not getting any content. In case of PDF files I am getting blank white screen.

Below is the block of code I am using to fetch the document from S3 in Node wrapper API and relay the same response.

const request = require('request');

request(s3SignedURL, function (error, result, body) {
    if (!error) {
        res.header('Content-Type','application/pdf');
        res.end(body);
    } else {
        res.status(500).send(error);
    }
});

[EDIT]

I am storing the details of file uploaded S3 in an table and using that table to fetch the document when someone tries to access it. Below is the complete code used.

const S3 = new AWS.S3();

app.get("/getFile/*", function (req, res) {
    var urlInfo = req.url;
    var urlInfoList = urlInfo.split("/");
    var accessCode = urlInfoList[2];
    var accessID = urlInfoList[3];

    if (!!accessID && !!accessCode) {
        db.getFileInfo(accessCode, accessID).then(function (fileInfo) {
            if (fileInfo.length > 0) {
                var S3Options = {
                    Bucket: Bucketname,
                    Key: fileInfo[0].fileS3Key,
                };
                S3.getObject(S3Options, function (err, data) {
                    res.attachment(fileInfo[0].fileS3Key);
                    res.send(data.Body);
                });

                // request(fileInfo[0].fileS3URL).pipe(res.set('Content-Type', 'application/pdf').set('Content-Disposition', 'inline'));
            } else {
                res.status(404).send("<html><head><title>404 Not Found</title></head><body bgcolor=\"white\"><center><h1>404 Not Found</h1></center><hr></body></html>");
            }
        }, function (fileErr) {
            console.log('fileErr');
            console.log(fileErr);
            res.status(404).send("<html><head><title>404 Not Found</title></head><body bgcolor=\"white\"><center><h1>404 Not Found</h1></center><hr></body></html>");
        });
    } else {
        res.status(404).send("<html><head><title>404 Not Found</title></head><body bgcolor=\"white\"><center><h1>404 Not Found</h1></center><hr></body></html>");
    }
});

Any help in this regard will be very useful.


Solution

  • You are getting a blank screen because you need to send the Content-Disposition parameter as well.

    By the way, the purpose of the pre-signed url is to get temporary access to s3 objects from environments that are publicly exposed (outside AWS environment) . You don't have to use pre-signed URL mechanism from a backend service where you can access the object securely via SDK

    const express = require('express');
    const app = express();
    const request = require('request');
    
    app.get('/download-file', function (req, res) {
    
      // sdk way
      var s3 = new AWS.S3({});
      var options = {
        Bucket: 'my-bucket-name',
        Key: file,
      };
      s3.getObject(options, function (err, data) {
        res.setHeader('Content-disposition', `inline; filename="${filename}"`);
        res.end(data.Body, 'binary');
      });
    
      // http way
      request('https://s3-ap-southeast-2.amazonaws.com/my-bucket-name/mypdf.pdf')
        .pipe(res.set('Content-Type', 'application/pdf').set('Content-Disposition', 'inline; filename="mypdf.pdf"'))
    })