使用Node将上载的文件流式传输到Azure blob存储

Cha*_*own 12 azure azure-storage-blobs node.js express

使用Express with Node,我可以成功上传文件并将其传递到以下代码块中的Azure存储.

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 path = req.files.snapshot.path;
    var bs= azure.createBlobService();
    bs.createBlockBlobFromFile('c', 'test.png', path, function (error) { });
    res.send("OK");
});
Run Code Online (Sandbox Code Playgroud)

这很好用,但Express会创建一个临时文件并先存储图像,然后我从文件中将其上传到Azure.这似乎是一个低效且不必要的步骤,我最终必须管理临时文件目录的清理.

我应该能够使用blobService.createBlockBlobFromStreamAzure SDK中的方法将文件直接流式传输到Azure存储,但我不熟悉Node或Express以了解如何访问流数据.

app.post('/upload', function (req, res) {

    var stream = /// WHAT GOES HERE ?? ///

    var bs= azure.createBlobService();
    bs.createBlockBlobFromStream('c', 'test.png', stream, function (error) { });
    res.send("OK");
});
Run Code Online (Sandbox Code Playgroud)

我发现以下博客表明可能有办法这样做,当然Express也会抓取流数据并解析并将其保存到文件系统中.http://blog.valeryjacobs.com/index.php/streaming-media-from-url-to-blob-storage/

vjacobs代码实际上是从另一个站点下载文件并将该流传递给Azure,所以我不确定它是否可以适应我的情况.

如何使用Node访问上传的文件流并将其直接传递给Azure?

Cha*_*own 15

解决方案(基于与@danielepolencic的讨论)

使用Multiparty(npm install multiparty),一个Formidable的分支,如果我们从Express中禁用bodyparser()中间件,我们可以访问多部分数据(有关更多信息,请参阅有关此操作的说明).与Formidable不同,除非您告知,否则Multiparty不会将文件流式传输到磁盘.

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');
});
Run Code Online (Sandbox Code Playgroud)

@danielepolencic的道具帮助找到解决方案.


dan*_*cic 7

您可以从连接中间件文档中读取,bodyparser自动为您处理表单.在您的特定情况下,它会解析传入的多部分数据并将其存储在其他位置,然后以一种不错的格式(即req.files)公开保存的文件.

不幸的是,我们不需要(和必要的)黑魔法主要是因为我们希望能够直接将输入数据流式传输到azure而不会碰到磁盘(即req.pipe(res)).因此,我们可以关闭bodyparser中间件并自己处理传入的请求.在引擎盖下,bodyparser使用node-formidable,因此在我们的实现中重用它可能是个好主意.

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);
Run Code Online (Sandbox Code Playgroud)

核心思想是我们可以利用节点流,这样我们就不需要在将文件发送到azure之前在内存中加载完整文件,但我们可以在它出现时进行传输.node-formidable模块支持流,因此将流连接到azure将实现我们的目标.

您可以通过使用以下命令替换post路径,轻松地在本地测试代码而无需达到azure :

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

在这里,我们只是将请求从输入传递到输出.你可以bodyParser 在这里阅读更多信息.