8

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 によると、multipart/form-data 解析用に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);
    });
};

最終編集:

これは、別の開発者からコピーして変更した単純な実装です。これは私のために働いています:(私はまだ元のエクスプレスアプリでなぜそれが機能しないのかを理解しようとしています.何かが干渉しているようです)

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

2 に答える 2

5

githubで作成した問題に関する私のコメントを参照してください。私は同じ問題を抱えていましたが、問題をデバッグすることができました。問題がリクエストを変更した高速ミドルウェアであると確信できるところまで絞り込みました。ありそうもない犯人が見つかるまで、ミドルウェアを 1 つずつ無効にしました: connect-livereload

app.use(require('connect-livereload')()); をコメントアウトしました。そして問題はなくなりました。livereload スクリプトをレスポンス (バイナリ イメージ ファイル) に挿入していたと思います。

于 2015-06-26T18:01:39.180 に答える
3

ファイルが HTML フォームを介してアップロードされたようです。その場合、multipart/form-dataでエンコードされたデータをデコードし、必要に応じてパーツを再構築し、ファイルをGridFSに保存する必要があります。解析には、 node-multipartyなどを使用できます。

于 2015-05-07T18:51:20.020 に答える