2016-03-03 16 views
13

hakkında bilgi içeren Express ile S3'ten gelen akış dosyası aws-sdk modülünü ve Express 4.13'ü kullanarak, S3'ten bir dosyaya çeşitli yollarla proxy uygulamak mümkündür.Uzunluk ve filetype

Bu geri arama sürüm Content-Length gibi bir tampon artı diğer ilgili başlıkları gibi dosya gövde metni olacaktır:

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 

    }); 

} 

bu sürümü ile sorun olan göndermeden önce tüm dosyayı almak zorunda olmasıdır Büyük değil, özellikle video gibi büyük bir şey varsa.

Bu sürüm dosyayı doğrudan akışı olacak:

function(req,res){ 

    var s3 = new AWS.S3(); 

    s3.getObject({Bucket: myBucket, Key: myFile}) 
    .createReadStream() 
    .pipe(res); 

} 

Ama ilkinden farklı olarak, bir tarayıcı düzgün dosyayı işlemek gerekebilir Üstbilgilerinde hakkında hiçbir şey yapmayacaktır.

Her iki dünyanın en iyisini elde etmenin, S3'ten doğru başlıklardan geçmenin, ancak dosyayı akış olarak göndermenin bir yolu var mı? İlk önce meta verileri almak için S3'e HEAD isteği yapılarak yapılabilir, ancak bir API çağrısı ile yapılabilir mi?

cevap

10

Projemde yalnızca nesne meta verilerini almak için headObject yapıyorum (gerçekten hızlı ve nesneyi indirmekten kaçınıyor). Sonra yanıtımızda boru için yaymak için gereken tüm başlıkları ekleyin:

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); 
    }); 
+0

Bu mükemmel. Teşekkürler! – matthoiland

+0

Yani bir yerine iki HTTP isteği yapmayı tercih edersiniz? –

15

Bir yaklaşım httpHeaders olayı dinleme ve içinde bir akış yaratıyor. Böyle bir sey yapabiliriz, bizim güzergah işleyicilerindeki,

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); 
};  

Sonra: André Werlang cevabı üzerine

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(); 
4

bina edilen bir forwardToExpress yöntemle aws Request nesneleri geliştirmek için aşağıdaki yapmış

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

Bu aslında bizim yaptığımız şey. Yaymak istediğiniz başlık kümesinin (aralık isteklerini ve eTag tabanlı istemci önbelleğe almayı desteklemek istediğinizi varsayarak) muhtemelen: ['kabul aralıkları', 'içerik uzunluğu', 'içerik aralığı', 'içerik -type ',' etag ',' son değiştirilmiş ']. – BobDickinson