Frage Speichern eines auf s3 gespeicherten Bildes mit node.js?


Ich versuche, einen Image-Server zu schreiben, der node.js verwendet, um Bilder auf s3 zu speichern. Das Hochladen des Bildes funktioniert gut und ich kann es mit einem s3 Browser Client herunterladen und anzeigen (ich benutze insbesondere Dragondisk, aber ich habe es erfolgreich auch mit anderen heruntergeladen), aber wenn ich es mit Knoten herunterlade und es versuche um es auf die Festplatte zu schreiben, kann ich die Datei nicht öffnen (sie besagt, dass sie beschädigt sein könnte oder ein Dateiformat verwendet, das von der Vorschau nicht erkannt wird). Ich benutze den Amazon Sdk für Knoten und fs, um die Datei zu schreiben. Ich weiß, dass Sie eine optionale Codierung an fs.writeFile übergeben können, aber ich habe sie alle ausprobiert und es funktioniert nicht. Ich habe auch versucht, ContentType auf putObject und ResponseContentType auf getObject sowie ContentEncoding und ResponseContentEncoding (und all diese Dinge in verschiedenen Kombinationen) zu setzen. Gleiches Ergebnis. Hier ist ein Code:

var AWS = require('aws-sdk')
  , gm = require('../lib/gm')
  , uuid = require('node-uui')
  , fs = require('fs');

AWS.config.loadFromPath('./amazonConfig.json');
var s3 = new AWS.S3();

var bucket = 'myBucketName'; // There's other logic here to set the bucket name.

exports.upload = function(req, res) {
    var id = uuid.v4();
    gm.format("/path/to/some/image.jpg", function(format){
        var key = req.params.dir + "/" + id + "/default." + format;
        fs.readFile('/path/to/some/image.jpg', function(err, data){
            if (err) { console.warn(err); }
            else {
                s3.client.putObject({
                    Bucket: bucket,
                    Key: key,
                    Body: data,
                    ContentType: 'image/jpeg'
                    // I've also tried adding ContentEncoding (in various formats) here.
                 }).done(function(response){
                    res.status(200).end(JSON.stringify({ok:1, id: id}));
                }).fail(function(response){
                    res.status(response.httpResponse.statusCode).end(JSON.stringify(({err: response})));
                });
            }
        });
    });
};

exports.get = function(req, res) {
    var key = req.params.dir + "/" + req.params.id + "/default.JPEG";
    s3.client.getObject({
        Bucket: bucket, 
        Key:  key,
        ResponseContentType: 'image/jpeg'
        // Tried ResponseContentEncoding here in base64, binary, and utf8
    }).done(function(response){
        res.status(200).end(JSON.stringify({ok:1, response: response}));
        var filename = '/path/to/new/image/default.JPEG';
        fs.writeFile(filename, response.data.Body, function(err){
            if (err) console.warn(err);
            // This DOES write the file, just not as an image that can be opened.
            // I've tried pretty much every encoding as the optional third parameter
            // and I've matched the encodings to the ResponseContentEncoding and
            // ContentEncoding above (in case it needs to be the same)
        });
    }).fail(function(response){
        res.status(response.httpResponse.statusCode).end(JSON.stringify({err: response}));
    });
};

Übrigens benutze ich express für das Routing, von daher kommt req.params.


8
2017-12-20 19:59


Ursprung


Antworten:


Für Leute, die immer noch mit diesem Problem kämpfen. Hier ist der Ansatz, den ich mit nativen aws-sdk verwendet habe.

var AWS = require('aws-sdk');
AWS.config.loadFromPath('./s3_config.json');
var s3Bucket = new AWS.S3( { params: {Bucket: 'myBucket'} } );

in Ihrer Router-Methode: - ContentType sollte auf den Inhaltstyp der Bilddatei festgelegt werden

  buf = new Buffer(req.body.imageBinary.replace(/^data:image\/\w+;base64,/, ""),'base64')
  var data = {
    Key: req.body.userId, 
    Body: buf,
    ContentEncoding: 'base64',
    ContentType: 'image/jpeg'
  };
  s3Bucket.putObject(data, function(err, data){
      if (err) { 
        console.log(err);
        console.log('Error uploading data: ', data); 
      } else {
        console.log('succesfully uploaded the image!');
      }
  });

s3_config.json Datei ist: -

{
  "accessKeyId":"xxxxxxxxxxxxxxxx",
  "secretAccessKey":"xxxxxxxxxxxxxx",
  "region":"us-east-1"
}

11
2017-09-30 02:02



Ok, nach langem Ausprobieren habe ich herausgefunden, wie das geht. Ich wechselte zu knox, aber vermutlich könnte man eine ähnliche Strategie mit aws-sdk verwenden. Das ist die Art von Lösung, die mich dazu bringt, zu sagen: "Es muss einen besseren Weg geben als das", aber ich bin mit allem, was funktioniert, an diesem Punkt zufrieden.

var imgData = "";
client.getFile(key, function(err, fileRes){
    fileRes.on('data', function(chunk){
        imgData += chunk.toString('binary');
    }).on('end', function(){
        res.set('Content-Type', pic.mime);
        res.set('Content-Length', fileRes.headers['content-length']);
        res.send(new Buffer(imgData, 'binary'));
    });
});

getFile() gibt Datenblöcke als Puffer zurück. Man könnte meinen, man könnte die Ergebnisse direkt an das Front-End leiten, aber aus irgendeinem Grund war dies der EINZIGE Weg, wie ich den Service dazu bringen konnte, ein Bild korrekt zurückzugeben. Es fühlt sich überflüssig an, einen Puffer in einen binären String zu schreiben, nur um ihn in einen Puffer zu schreiben, aber hey, wenn es funktioniert, funktioniert es. Wenn jemand eine effizientere Lösung findet, würde ich es gerne hören.


5
2018-01-03 20:08