Node.jsfile upload(Express 4,MongoDB,GridFS,GridFSstream)

我正在尝试在我的node.js应用程序中设置一个文件API。 我的目标是能够直接将文件stream写入到gridfs,而不需要最初将文件存储到磁盘。 这看起来像我的创build代码正在工作。 我能够保存file upload到网格。 问题是阅读文件。 当我尝试通过networking浏览器窗口下载保存的文件时,我发现文件内容包装了如下内容:

------WebKitFormBoundarye38W9pfG1wiA100l Content-Disposition: form-data; name="file"; filename="myfile.txt" Content-Type: text/javascript ***File contents here*** ------WebKitFormBoundarye38W9pfG1wiA100l-- 

所以我的问题是我需要做什么从文件stream中剥离边界信息,然后将其保存到gridfs? 这是我正在使用的代码:

 'use strict'; var mongoose = require('mongoose'); var _ = require('lodash'); var Grid = require('gridfs-stream'); Grid.mongo = mongoose.mongo; var gfs = new Grid(mongoose.connection.db); // I think this works. I see the file record in fs.files exports.create = function(req, res) { var fileId = new mongoose.Types.ObjectId(); var writeStream = gfs.createWriteStream({ _id: fileId, filename: req.query.name, mode: 'w', content_type: req.query.type, metadata: { uploadedBy: req.user._id, } }); writeStream.on('finish', function() { return res.status(200).send({ message: fileId.toString() }); }); req.pipe(writeStream); }; // File data is returned, but it's wrapped with // WebKitFormBoundary and has headers. exports.read = function(req, res) { gfs.findOne({ _id: req.params.id }, function (err, file) { if (err) return res.status(400).send(err); // With this commented out, my browser will prompt // me to download the raw file where I can see the // webkit boundary and request headers //res.writeHead(200, { 'Content-Type': file.contentType }); var readstream = gfs.createReadStream({ _id: req.params.id // I also tried this way: //_id: file._id }); readstream.pipe(res); }); }; 

顺便说一句,我目前没有使用这些路线的任何中间件,但我愿意这样做。 我只是不希望该文件在发送到网格之前先打开磁盘。

编辑:

Per @fardjad,我添加了节点multiparty模块multipart / form-dataparsing和它的工作。 但是,当我下载一个上传的文件,并与原文(作为文本)进行比较,编码有很多不同之处,下载的文件将不会打开。 这是我最近的尝试。

 'use strict'; var mongoose = require('mongoose'); var _ = require('lodash'); var multiparty = require('multiparty'); var Grid = require('gridfs-stream'); Grid.mongo = mongoose.mongo; var gfs = new Grid(mongoose.connection.db); exports.create = function(req, res) { var form = new multiparty.Form(); var fileId = new mongoose.Types.ObjectId(); form.on('error', function(err) { console.log('Error parsing form: ' + err.stack); }); form.on('part', function(part) { if (part.filename) { var writeStream = gfs.createWriteStream({ _id: fileId, filename: part.filename, mode: 'w', content_type: part.headers['content-type'], metadata: { uploadedBy: req.user._id, } }) part.pipe(writeStream); } }); // Close emitted after form parsed form.on('close', function() { return res.status(200).send({ message: fileId.toString() }); }); // Parse req form.parse(req); }; exports.read = function(req, res) { gfs.findOne({ _id: req.params.id }, function (err, file) { if (err) return res.status(400).send(err); res.writeHead(200, { 'Content-Type': file.contentType }); var readstream = gfs.createReadStream({ _id: req.params.id }); readstream.pipe(res); }); }; 

最终编辑:

这是一个简单的实现,我从另一个开发人员复制和修改。 这对我来说是工作的(我仍然试图找出为什么它不能在我原来的快速应用程序中工作,似乎是有些干扰)

https://gist.github.com/pos1tron/094ac862c9d116096572

 var Busboy = require('busboy'); // 0.2.9 var express = require('express'); // 4.12.3 var mongo = require('mongodb'); // 2.0.31 var Grid = require('gridfs-stream'); // 1.1.1" var app = express(); var server = app.listen(9002); var db = new mongo.Db('test', new mongo.Server('127.0.0.1', 27017)); var gfs; db.open(function(err, db) { if (err) throw err; gfs = Grid(db, mongo); }); app.post('/file', function(req, res) { var busboy = new Busboy({ headers : req.headers }); var fileId = new mongo.ObjectId(); busboy.on('file', function(fieldname, file, filename, encoding, mimetype) { console.log('got file', filename, mimetype, encoding); var writeStream = gfs.createWriteStream({ _id: fileId, filename: filename, mode: 'w', content_type: mimetype, }); file.pipe(writeStream); }).on('finish', function() { // show a link to the uploaded file res.writeHead(200, {'content-type': 'text/html'}); res.end('<a href="/file/' + fileId.toString() + '">download file</a>'); }); req.pipe(busboy); }); app.get('/', function(req, res) { // show a file upload form res.writeHead(200, {'content-type': 'text/html'}); res.end( '<form action="/file" enctype="multipart/form-data" method="post">'+ '<input type="file" name="file"><br>'+ '<input type="submit" value="Upload">'+ '</form>' ); }); app.get('/file/:id', function(req, res) { gfs.findOne({ _id: req.params.id }, function (err, file) { if (err) return res.status(400).send(err); if (!file) return res.status(404).send(''); res.set('Content-Type', file.contentType); res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"'); var readstream = gfs.createReadStream({ _id: file._id }); readstream.on("error", function(err) { console.log("Got error while processing stream " + err.message); res.end(); }); readstream.pipe(res); }); }); 

看到我对你在github上创build的问题的评论。 我有同样的问题,但我设法debugging的问题。 我把它缩小到了我所确信的问题是一个快速中间件修改了请求。 我一个一个地禁用了我的中间件,直到find不可能的罪魁祸首:connect-livereload

我注释掉了app.use(require('connect-livereload')()); 问题就消失了。 我相信这是注入响应(二进制图像文件)的livereload脚本。

看起来像文件已经通过HTML表单上传,在这种情况下,您需要解码多部分/表单数据编码的数据,如果需要重新组装部件,并将文件保存到GridFS 。 为了parsing,你可以使用类似node-multiparty的东西。