我正在使用带有express的node.js编写API。部分API将允许用户将大量二进制数据(可能数百MB)的有效负载存储在服务器数据库中。
现在,快速请求处理程序在整个上传准备就绪并且存储在服务器(req.body)的内存中之前不会被调用。然后它必须保存到数据库。有两件事我不喜欢这个。首先,它需要大量的服务器内存来同时保存所有二进制数据。第二个是像MongoDB和S3这样的许多数据库允许流式传输,因此在开始编写之前你并不需要掌握所有数据,因此没有理由等待。
所以我的问题是,可以将节点(通过快速或其他方式)配置为在整个请求进入之前开始流式传输到数据库吗?
答案 0 :(得分:3)
经过进一步的研究,我发现原生的“http”模块确实支持我提到的方式的流媒体。我不确定express是否支持这一点。我猜它确实如此,但在上传的情况下你可能无法使用bodyParser中间件,因为这可能会阻塞,直到收到整个请求体。
无论如何,这里有一些代码显示如何将传入请求流式传输到MongoDB的GridFS:
var http = require('http');
var mongo = require('mongodb');
var db = new mongo.Db('somedb', new mongo.Server("localhost", 27017), { safe: true });
db.open(function(err) {
if (err)
console.log(err);
http.createServer(function(req, res) {
var numToSave = 0;
var endCalled = false;
new mongo.GridStore(db, new mongo.ObjectID(), "w", { root: "fs", filename: "test" }).open(function(err, gridStore) {
if(err)
console.log(err);
gridStore.chunkSize = 1024 * 256;
req.on("data", function(chunk) {
numToSave++;
gridStore.write(chunk, function(err, gridStore) {
if(err)
console.log(err);
numToSave--;
if(numToSave === 0 && endCalled)
finishUp(gridStore, res);
});
});
req.on("end", function() {
endCalled = true;
console.log("end called");
if(numToSave === 0)
finishUp(gridStore, res);
});
});
}).listen(8000);
});
function finishUp(gridStore, res) {
gridStore.close();
res.end();
console.log("finishing up");
}
要点是req对象实际上是一个包含“data”和“end”事件的流。每次发生“数据”事件时,都会向mongo写入一大块数据。发生“结束”事件时,关闭mongo连接并发送响应。
与协调所有不同的异步活动有关。在您有机会实际写出所有数据之前,您不希望关闭mongo连接。我用计数器和布尔值实现了这一点,但是使用某些库可能有更好的方法。