使用Express从S3stream文件,包括长度和文件types的信息

使用aws-sdk模块和Express 4.13,可以通过多种方式从S3中代理一个文件。

这个callback版本将返回文件正文作为缓冲区,加上其他相关的标题,如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 }); } 

这个版本的问题是你必须在发送之前得到整个文件,这并不是很好,特别是如果它像video一样大。

这个版本将直接传输文件:

 function(req,res){ var s3 = new AWS.S3(); s3.getObject({Bucket: myBucket, Key: myFile}) .createReadStream() .pipe(res); } 

但不像第一个,它不会做任何关于头文件,浏览器可能需要正确处理文件。

有没有办法获得两个世界的最好的,从S3传递正确的标题,但发送文件作为stream? 这可以通过首先向S3发送HEAD请求来获取元数据,但是可以通过一个API调用完成吗?

一种方法是监听httpHeaders事件并在其中创build一个stream。

 s3.getObject(params) .on('httpHeaders', function (statusCode, headers) { res.set('Content-Length', headers['content-length']); res.set('Content-Type', headers['content-type']); this.response.httpResponse.createUnbufferedStream() .pipe(res); }) .send(); 

对于我的项目,我只是做一个headObject,以便只检索对象元数据(这是非常快,避免下载对象)。 然后我在响应中添加所有需要为pipe道传播的标题:

  var s3 = new AWS.S3(); var params = { Bucket: bucket, Key: key }; s3.headObject(params, function (err, data) { if (err) { // an error occurred console.error(err); return next(); } var stream = s3.getObject(params).createReadStream(); // forward errors stream.on('error', function error(err) { //continue to the next middlewares return next(); }); //Add the content type to the response (it's not propagated from the S3 SDK) res.set('Content-Type', mime.lookup(key)); res.set('Content-Length', data.ContentLength); res.set('Last-Modified', data.LastModified); res.set('ETag', data.ETag); stream.on('end', () => { console.log('Served by Amazon S3: ' + key); }); //Pipe the s3 object to the response stream.pipe(res); }); 

基于AndréWerlang的回答,我们做了以下工作,用forwardToExpress方法来扩充AWS Request对象:

 const _ = require('lodash'); const AWS = require('aws-sdk'); AWS.Request.prototype.forwardToExpress = function forwardToExpress(res, next) { this .on('httpHeaders', function (code, headers) { if (code < 300) { res.set(_.pick(headers, 'content-type', 'content-length', 'last-modified')); } }) .createReadStream() .on('error', next) .pipe(res); }; 

那么,在我们的路由处理程序中,我们可以这样做:

 s3.getObject({Bucket: myBucket, Key: myFile}).forwardToExpress(res, next);