使用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?
答案 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
路径替换为:
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 {
...
}
,createWriteStreamToBlockBlob
,createBlockBlobFromStream
。
参考资料可以在这里找到: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)
(如果你不关心选项,请尝试一个空数组)参数。
奇怪的是,“选项”应该是可选的,但无论出于何种原因,如果我将其删除,我的选择就会失败。