Stream uploaded file to Azure blob storage with Node

后端 未结 4 1695
野的像风
野的像风 2020-12-13 21:18

Using Express with Node, I can upload a file successfully and pass it to Azure storage in the following block of code.

app.get(\'/upload\', function (req, re         


        
相关标签:
4条回答
  • 2020-12-13 21:52

    SOLUTION (based on discussion with @danielepolencic)

    Using Multiparty(npm install multiparty), a fork of Formidable, we can access the multipart data if we disable the bodyparser() middleware from Express (see their notes on doing this for more information). Unlike Formidable, Multiparty will not stream the file to disk unless you tell it to.

    app.post('/upload', function (req, res) {
        var blobService = azure.createBlobService();
        var form = new multiparty.Form();
        form.on('part', function(part) {
            if (part.filename) {
    
                var size = part.byteCount - part.byteOffset;
                var name = part.filename;
    
                blobService.createBlockBlobFromStream('c', name, part, size, function(error) {
                    if (error) {
                        res.send({ Grrr: error });
                    }
                });
            } else {
                form.handlePart(part);
            }
        });
        form.parse(req);
        res.send('OK');
    });
    

    Props to @danielepolencic for helping to find the solution to this.

    0 讨论(0)
  • 2020-12-13 21:59

    People having trouble with .createBlockBlobFromStream trying to implement the solutions, note that this method has been changed slightly in newer versions

    Old version:

    createBlockBlobFromStream(containerName, blobName, part, size, callback)
    

    New version

    createBlockBlobFromStream(containerName, blobName, part, size, options, callback)
    

    (if you don't care about options, try an empty array) for the parameter.

    Oddly enough, "options" is supposed to be optional, but for whatever reason, mine fails if I leave it out.

    0 讨论(0)
  • 2020-12-13 22:02

    As you can read from the connect middleware documentation, bodyparser automagically handles the form for you. In your particular case, it parses the incoming multipart data and store it somewhere else then exposes the saved file in a nice format (i.e. req.files).

    Unfortunately, we do not need (and necessary like) black magic primarily because we want to be able to stream the incoming data to azure directly without hitting the disk (i.e. req.pipe(res)). Therefore, we can turn off bodyparser middleware and handle the incoming request ourselves. Under the hood, bodyparser uses node-formidable, so it may be a good idea to reuse it in our implementation.

    var express = require('express');
    var formidable = require('formidable');
    var app = express();
    
    // app.use(express.bodyParser({ uploadDir: 'temp' }));
    
    app.get('/', function(req, res){
      res.send('hello world');
    });
    
    app.get('/upload', function (req, res) {
        res.send(
        '<form action="/upload" method="post" enctype="multipart/form-data">' +
        '<input type="file" name="snapshot" />' +
        '<input type="submit" value="Upload" />' +
        '</form>'
        );
    });
    
    app.post('/upload', function (req, res) {
      var bs = azure.createBlobService();
      var form = new formidable.IncomingForm();
      form.onPart = function(part){
        bs.createBlockBlobFromStream('taskcontainer', 'task1', part, 11, function(error){
          if(!error){
              // Blob uploaded
          }
        });
      };
      form.parse(req);
      res.send('OK');
    });
    
    app.listen(3000);
    

    The core idea is that we can leverage node streams so that we don't need to load in memory the full file before we can send it to azure, but we can transfer it as it comes along. The node-formidable module supports streams, hence piping the stream to azure will achieve our objective.

    You can easily test the code locally without hitting azure by replacing the post route with:

    app.post('/upload', function (req, res) {
      var form = new formidable.IncomingForm();
        form.onPart = function(part){
          part.pipe(res);
        };
        form.parse(req);
    });
    

    Here, we're simply piping the request from the input to the output. You can read more about bodyParser here.

    0 讨论(0)
  • 2020-12-13 22:06

    There are different options for uploading binary data (e.g. images) via Azure Storage SDK for Node, not using multipart.

    Based on the Buffer and Stream definitions in Node and manipulating them, these could be handled using almost all the methods for BLOB upload: createWriteStreamToBlockBlob, createBlockBlobFromStream, createBlockBlobFromText.

    References could be found here: Upload a binary data from request body to Azure BLOB storage in Node.js [restify]

    0 讨论(0)
提交回复
热议问题