2016-05-25 3 views
4

Ich versuche, S3-Dateispeicher in meine NodeJS-Anwendung zu integrieren. This tutorial zu erklären, wie direkt zu S3 hochladen ist sehr gut, aber es ist nicht für meine Bedürfnisse geeignet, wie ich will, dass die Dateien nur über meine Web-App-API zugänglich sind. Ich möchte nicht, dass die Dateien unter ihren S3-URLs öffentlich verfügbar sind, ich möchte nur, dass sie beispielsweise über /api/files/<user_id>/<item_id>/<filename> verfügbar sind.Dateien von Amazon S3 über den NodeJS-Server übergeben, ohne die S3-URL offen zu legen?

Der Grund, warum ich downloads durch meine API gehen möchte, ist, damit ich überprüfen kann, dass der Benutzer diese bestimmte Datei anzeigen darf.

Der Grund, warum ich mag Uploads auf meinen Server durchlaufen, so ist, dass ich weiß, welche <item_id> die Dateinamen zuweisen, da dies das gleiche wie seine MongoDB _id Eigenschaft sein. Ich kann das nicht tun, wenn ich die Datei in S3 hochlade, bevor der Gegenstand überhaupt einen Mongo _id hat.

Ich habe gesucht, konnte aber kein einfaches Tutorial finden, wie Dateien von S3 zum Client und umgekehrt durch meine NodeJS-Anwendung zu streamen.

Danke

Antwort

8

Eine Kombination aus einer Express-Middleware (um die Autorisierung des anfragenden Benutzers zu überprüfen) und die Verwendung des Node AWS SDK sollten den Trick machen.

Hier ist ein vollständiges Beispiel mit multer für den Upload.

var express = require('express'); 
var app = express(); 
var router = express.Router(); 
var multer = require('multer'); 
var upload = multer({ 
    dest: "tmp/" 
}); 
var fs = require('fs'); 
var async = require('async'); 
var AWS = require('aws-sdk'); 
// Configure AWS SDK here 
var s3 = new AWS.s3({ 
    params: { 
    Bucket: 'xxx' 
    } 
}); 

/** 
* Authentication middleware 
* 
* It will be called for any routes starting with /files 
*/ 
app.use("/files", function (req, res, next) { 
    var authorized = true; // use custom logic here 
    if (!authorized) { 
    return res.status(403).end("not authorized"); 
    } 
    next(); 
}); 

// Route for the upload 
app.post("/files/upload", upload.single("form-field-name"), function (req, res) { 
    var fileInfo = console.log(req.file); 
    var fileStream = fs.readFileSync(fileInfo.path); 
    var options = { 
    Bucket: 'xxx', 
    Key: 'yyy/'+fileName, 
    Body: fileStream 
    }; 

    s3.upload(options, function (err) { 
    // Remove the temporary file 
    fs.removeFileSync("tmp/"+fileInfo.path); // ideally use the async version 
    if (err) { 
     return res.status(500).end("Upload to s3 failed"); 
    } 
    res.status(200).end("File uploaded"); 
    }); 
}); 

// Route for the download 
app.get("/files/download/:name", function (req, res) { 
    var fileName = req.params.name; 
    if (!fileName) { 
    return res.status(400).end("missing file name"); 
    } 
    var options = { 
    Bucket: 'xxx', 
    Key: 'yyy/'+fileName 
    }; 
    res.attachment(fileName); 
    s3.getObject(options).createReadStream().pipe(res); 
}); 

app.listen(3000); 

Offensichtlich ist dies nur teilweise getestet und es fehlt der richtige Fehlerbehandlung - aber es hoffentlich sollte es Ihnen eine grobe Vorstellung davon, wie es zu implementieren.

+0

Vielen Dank dafür! Ich entschied mich, dies mit der s3-Bibliothek zu starten, die einige einfache Hilfsfunktionen zum Hoch- und Herunterladen bietet, aber ich werde diese Antwort als Referenz für andere Dinge verwenden. – Aron

+0

Beziehen Sie sich auf [node-s3-client] (https://github.com/andrewrk/node-s3-client)? Wenn ja, muss ich dich warnen, ich habe sehr schlechte Erfahrungen damit gemacht. Siehe zum Beispiel [Ausgabe # 127] (https://github.com/andrewrk/node-s3-client/issues/127), [Ausgabe # 121] (https://github.com/andrewrk/node-s3- Kunde/Ausgaben/121) – christophetd

+0

Oh. Ja, das ist es. Hmmm:/Ok ich bleibe dabei für die Prototyp-Phase, werde es aber für Phase 2 tun. – Aron

2

Sie S3 REST API verwenden können. Es ermöglicht Ihnen, eine signierte Anfrage an GET oder PUT Ihre Bucket-Objekte direkt von Ihrem Backend zu machen.

Das Prinzip ist ähnlich wie in Ihrem Link beschrieben. Ihr Back-End muss die AWS JS SDK verwenden, um eine signierte URL zu erstellen, um ein Objekt zu manipulieren. Es steht Ihnen frei, vor oder nach der Anfrage von S3 in Ihren Express-Routen eine Überprüfung durchzuführen.

Hier ist ein einfaches GET Beispiel (es ist nicht voll funktionsfähig ist, nur die Hauptidee):

... 
[assume that you are in an express route with req/res objects] 
... 
var aws = require('aws-sdk'), 
    s3 = new aws.S3(); 

aws.config.region = 'your_region'; 
aws.config.credentials = { 
    accessKeyId: 'your_key', 
    secretAccessKey: 'your_secret' 
}; 

s3.getSignedUrl('getObject', {Bucket: 'your_bucket', Key: 'your_file_name', Expires: 3600}, function (error, url) { 
    if (error || !url) { 
    //error while creating the URL 
    res.status(500).end(); 
    } else { 
    //make a request to the signed URL to get the file and pipe the res to the client 
    request({ 
     url: url 
    }).pipe(res); 
    } 
}); 

Sie here weitere Beispiele von Amazon finden.