Using the aws-sdk
module and Express 4.13, it's possible to proxy a file from S3 a number of ways.
This callback version will return the file body as a buffer, plus other relevant headers like Content-Length
:
function(req,res){
var s3 = new AWS.S3();
s3.getObject({Bucket: myBucket, Key: myFile},function(err,data){
if (err) {
return res.status(500).send("Error!");
}
// Headers
res.set("Content-Length",data.ContentLength)
.set("Content-Type",data.ContentType);
res.send(data.Body); // data.Body is a buffer
});
}
The problem with this version is that you have to get the entire file before sending it, which is not great, especially if it's something large like a video.
This version will directly stream the file:
function(req,res){
var s3 = new AWS.S3();
s3.getObject({Bucket: myBucket, Key: myFile})
.createReadStream()
.pipe(res);
}
But unlike the first one, it won't do anything about the headers, which a browser might need to properly handle the file.
Is there a way to get the best of both worlds, passing through the correct headers from S3 but sending the file as a stream? It could be done by first making a HEAD
request to S3 to get the metadata, but can it be done with one API call?
For my project, I simply do a headObject in order to retrieve the object metadata only (it's really fast and avoid to download the object). Then I add in the response all the headers I need to propagate for the piping:
One approach is listening the
httpHeaders
event and creating a stream within it.Building on André Werlang's answer, we have done the following to augment AWS
Request
objects with aforwardToExpress
method:Then, in our route handlers, we can do something like this: