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

时间:2013-08-19 15:47:22

标签: node.js azure express azure-storage-blobs

使用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");
});

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

我应该能够使用Azure SDK中的blobService.createBlockBlobFromStream方法将文件直接流式传输到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");
});

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

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

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

4 个答案:

答案 0 :(得分: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');
});

支持@danielepolencic寻求帮助找到解决方案。

答案 1 :(得分:7)

正如您可以从connect middleware documentation中读到的那样,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);

核心思想是我们可以利用node streams,这样我们就不需要在将内容发送到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);
});

在这里,我们只是将请求从输入传递到输出。您可以详细了解bodyParser here

答案 2 :(得分:1)

通过Azure Storage SDK for Node上传二进制数据(例如图像)有不同的选项,而不是使用多部分。

基于Node中的Buffer和Stream定义并对其进行操作,可以使用几乎所有BLOB上传方法来处理这些定义:@Configuration @EnableGlobalMethodSecurity public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration { @Override protected MethodSecurityExpressionHandler createExpressionHandler() { return new OAuth2MethodSecurityExpressionHandler(); } } @Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { ... } @Configuration @Import({ SecurityConfiguration.class, MethodSecurityConfiguration.class }) public class AppConfiguration { ... } createWriteStreamToBlockBlobcreateBlockBlobFromStream

参考资料可以在这里找到:Upload a binary data from request body to Azure BLOB storage in Node.js [restify]

答案 3 :(得分:0)

人们在.createBlockBlobFromStream尝试实现解决方案时遇到问题,请注意此方法在较新版本中略有改变

旧版本:

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

新版

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

(如果你不关心选项,请尝试一个空数组)参数。

奇怪的是,“选项”应该是可选的,但无论出于何种原因,如果我将其删除,我的选择就会失败。