7

node.js uygulamasında bir dosya API'si kurmaya çalışıyorum. Amacım, dosya akışını başlangıçta diske kaydetmeye gerek kalmadan dosya akışını doğrudan gridfs'e yazabilmektir. Oluşturma kodumun çalıştığı anlaşılıyor. Bir dosya yüklemesini gridfs'e kaydedebiliyorum. Sorun dosyayı okuyor. Bir web tarayıcı penceresinde aracılığıyla kaydedilmiş bir dosyayı indirmek için çalışırken, dosya içeriği gibi bir şeyle sarılmış görüyoruz aşağıdadır:Node.js Dosya Yükleme (Express 4, MongoDB, GridFS, GridFS Akışı)

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

***File contents here*** 

------WebKitFormBoundarye38W9pfG1wiA100l-- 

Benim soru ben sınır bilgiyi şerit yapmanız gereken şey bu dosya akışından gridfs'e kaydetmeden önce? Ben şu anda bu rotalar için herhangi katman kullanarak, ama bunu yaparken açığım değilim, arada

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

: Burada i ile çalışıyorum kod. Sadece dosyaya gridfs gönderilmeden önce diske vurmak istemedim.

Düzenleme: @fardjad başına

, bir çok parçalı/form-ayrıştırma için node-multiparty modülü ilave edildi ve bu tür çalıştı. Ancak yüklenen bir dosyayı indirdiğimde ve bir orijinal ile (metin olarak) karşılaştırdığımda, kodlamada birçok fark vardır ve indirilen dosya açılmaz. İşte en son denemem.

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

Final Düzenleme:

Burada başka bir geliştirici ve modifiye kopyalanmış basit uygulama var. Bu benim için çalışıyor: (Hala benim orijinal ekspres app çalışmaz anlamaya çalışıyorum şey engel gibi görünüyor.) Dosyası var gibi

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

cevap

5

github üzerinde oluşturduğunuz sorun hakkındaki yorumuma bakın. Aynı sorunu yaşadım ama sorunu ayıklamayı başardım. Sorunun, değiştirilen orta katmandaki bir soruyu değiştirdiğinden emin olduğum yere daraltdım. Ben olasılıksız suçlu bulmak kadar middleware tek tek devre dışı bıraktım: connect-livereload

Ben app.use yorumladı (require ('connect-livereload')()); ve sorun gitti. Karaciğereload komut dosyasını yanıta (ikili bir görüntü dosyası) enjekte ettiğine inanıyorum.

+0

Nihayetinde orijinal sorunuma neden olan şey bu, doğru yanıt olarak işaretliyorum. –

3

görünüyor bir HTML formu ile yüklendi, bu durumda multipart/form-data kodlu verileri deşifre etmeniz gerekiyor, gerekirse parçaları yeniden birleştirin ve dosyayı GridFS'a kaydedin. Ayrıştırma için node-multiparty gibi bir şey kullanabilirsiniz.

+0

Teşekkürler! İhtiyacım olan buydu. Düğüm-çok partili nasıl bütünleştirdiğimi gösteren soruna bazı güncellenmiş kod ekledim. –

+0

Sanırım çok erken konuştum. Yukarıda eklediğim en son kodu kullanarak, bir dosyayı karşıya yükleme sürecinde, daha sonra dosyayı kodlayarak değiştiriyor. PDF'ler ve JPEG'lerle çalışıyorum. Metin olarak orijinal bir kopyasını yüklenen ve daha sonra yüklenen bir dosyayla karşılaştırırsam, her birinde bulunan karakterler arasında çok fazla fark vardır. Herhangi bir fikir? –

+0

Soruyu çalışma koduyla güncelledim. Ben [busboy] (https://github.com/mscdex/busboy) kullanarak bitti ama çok partili muhtemelen de işe yarayacaktı. –