当前位置: 首页 > 面试题库 >

Node.js文件上传(Express 4,MongoDB,GridFS,GridFS-Stream)

高海阳
2023-03-14
问题内容

我试图在我的node.js应用程序中设置文件API。我的目标是能够直接将文件流写入gridfs,而无需最初将文件存储到磁盘。似乎我的创建代码正在运行。我能够将文件上传保存到gridfs。问题是正在读取文件。当我尝试通过Web浏览器窗口下载保存的文件时,看到文件内容包裹着以下内容:

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

***File contents here***

------WebKitFormBoundarye38W9pfG1wiA100l--

所以我的问题是,在将文件保存到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);
    });
};

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

编辑:

对于每个@fardjad,我添加了用于多部分/表单数据解析的node-
multiparty
模块,并且这种方法可行。但是,当我下载一个上传的文件并与原始文件(以文本形式)进行比较时,编码存在很多差异,并且下载的文件将无法打开。这是我最近的尝试。

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

最终编辑:

这是我从另一个开发人员复制并修改的简单实现。这对我有用:(我仍在尝试弄清楚为什么它在我的原始Express应用程序中不起作用。似乎有些干扰)

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上创建的问题的评论。我遇到了同样的问题,但是我设法调试了该问题。我将其范围缩小到我确信问题出在某个快速中间件修改了请求的位置。我一一禁用了中间件,直到发现了不太可能的罪魁祸首:connect-
livereload

我注释掉了app.use(require(’connect-livereload’)());
问题就解决了。我相信它是将livereload脚本注入响应(一个二进制图像文件)中。



 类似资料:
  • 主要内容:将文件添加到 GridFSGridFS 是 MongoDB 的一种规范,用于存储和检索大型文件,如图像、音频、视频等。GridFS 也是一种存储文件的文件系统,但其数据是存储在 MongoDB 集合中的,GridFS 甚至可以存储超过 16MB 的文件。在存储文件时 GridFS 可以将一个文件分为多个数据块,并将每个数据块存储在一个单独的文档中,每个文档最大为 255KB。 默认情况下,GridFS 使用 fs.file

  • 问题内容: 我有一个博客系统,可将上传的文件存储到GridFS系统中。问题是,我不知道如何查询它! 我将Mongoose与尚未支持GridFS的NodeJS一起使用,因此我将实际的mongodb模块用于GridFS操作。没有SEEM可以像常规集合中的文档一样查询文件元数据。 将元数据存储在指向GridFS objectId的文档中是否明智?可以轻松查询? 任何帮助将不胜感激,我有点卡住了:/ 问题

  • 问题内容: 我有一个将文件保存到gridfs的功能。重构后,它以某种方式停止工作,我花了两个多小时呆呆地盯着它。我发誓它与以前大致相同。我似乎记得起初在添加内容之前它不起作用,然后开始起作用,但这可能是失眠。从本质上讲,问题在于db.fs.files集合没有任何记录,但是将块添加到db.fs.chunks中。 数据 是通过fs.readFile()从磁盘加载的缓冲区 问题答案: 有两种解决方案。您

  • BuguFS类 bugu-mongo通过BuguFS类来操作GridFS文件系统,能够实现对文件的保存、获取、删除、重命名、移动等操作。 创建BuguFS对象 bugu-mongo框架提供了工厂类BuguFSFactory,用于创建BuguFS对象: public BuguFS create() public BuguFS create(String bucket) public BuguFS

  • “GridFS”是用于存储和检索文件的规范。在主窗口中,点击 “GridFS”来打开 GridFS 的对象列表。 你可以在数据库中创建多个存储桶以存储文件。点击 “新建存储桶”并输入存储桶的名。 若要打开已选择的存储桶,请点击 “打开存储桶”。 存储桶查看器 “存储桶查看器”是一个用于设计 GridFS 存储桶的 Navicat 基本工具。你可以上载,下载和查看存储桶内的 GridFS 文件。 按

  • “GridFS”是用于存储和检索文件的规范。在主窗口中,点击 “GridFS”来打开 GridFS 的对象列表。 你可以在数据库中创建多个存储桶以存储文件。点击 ”并输入存储桶的名。 若要打开已选择的存储桶,请点击 。 存储桶查看器 “存储桶查看器”是一个用于设计 GridFS 存储桶的 Navicat 基本工具。你可以上载,下载和查看存储桶内的 GridFS 文件。 按钮 描述 打开已选择的 G