将节点上传的文件stream式传输到Azure blob存储

使用Express与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创build一个临时文件并首先存储图像,然后从file upload到Azure。 这似乎是一个低效率和不必要的步骤,我最终不得不pipe理临时文件目录的清理。

我应该可以使用Azure SDK中的blobService.createBlockBlobFromStream方法将文件直接stream式传输到Azure存储,但是我不太了解Node或Express以了解如何访问stream式数据。

 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也是抓取stream数据并parsing并保存到文件系统中。 http://blog.valeryjacobs.com/index.php/streaming-media-from-url-to-blob-storage/

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

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

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

使用Multiparty(npm install multiparty)是一个Formidable的分支,如果我们从Express中禁用了bodyparser()中间件,可以访问多部分数据(有关更多信息,请参阅其注意事项)。 与Formidable不同,除非您告诉它,否则Multiparty不会将文件stream式传输到磁盘。

 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帮助find解决办法。

正如您可以从连接中间件文档中读取的, bodyparser自动为您处理表单。 在你的特定情况下,它parsing传入的多部分数据并将其存储在其他地方,然后以良好的格式(即req.files )公开保存的文件。

不幸的是,我们并不需要(也是必要的)黑魔法,主要是因为我们希望能够直接input数据到azure,而不会碰到磁盘(即req.pipe(res) )。 因此,我们可以closuresbodyparser中间件,自己处理收到的请求。 在这种情况下, bodyparser使用节点强大的 ,所以在我们的实现中重用它可能是一个好主意。

 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); 

其核心思想是我们可以利用节点stream,这样我们就不需要在完整的文件中加载完整的文件,然后我们就可以把它发送到azure色,但是我们可以随时传输它。 节点强大的模块支持stream,因此pipestream到azure色将实现我们的目标。

您可以轻松地在本地testing代码,而不用通过replacepostpath来达到azure色:

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

在这里,我们只是将input的请求输出到输出。 你可以在这里阅读更多关于bodyParser

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

根据Node中的Buffer和Stream定义并对其进行处理,可以使用几乎所有用于BLOB上载的方法来处理这些: createWriteStreamToBlockBlobcreateBlockBlobFromStreamcreateBlockBlobFromText

参考可以在这里find: 上传一个二进制数据从请求正文到Node.js中的Azure BLOB存储[restify]

使用.createBlockBlobFromStream尝试实现解决scheme时遇到问题,请注意,此方法在较新的版本中稍有变化

旧版:

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

新版本

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

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

奇怪的是,“选项”应该是可选的,但是无论出于何种原因,如果我把它排除在外,我的select就会失败。