Meteorは優れていますが、従来のファイルのアップロードをネイティブでサポートしていません。ファイルのアップロードを処理するいくつかのオプションがあります。
クライアントから、次を使用してデータを送信できます。
サーバー内、ファイルは次の場所に保存できます。
これらの方法の長所と短所は何ですか?また、それらを実装する最善の方法は何ですか?サードパーティのサイトへの保存やURLの取得など、他のオプションもあることを認識しています。
パッケージやサードパーティを使用せずに、Meteorを使用して非常に簡単にファイルをアップロードできます。
/*** client.js ***/
// asign a change event into input tag
'change input' : function(event,template){
var file = event.target.files[0]; //assuming 1 file only
if (!file) return;
var reader = new FileReader(); //create a reader according to HTML5 File API
reader.onload = function(event){
var buffer = new Uint8Array(reader.result) // convert to binary
Meteor.call('saveFile', buffer);
}
reader.readAsArrayBuffer(file); //read the file as arraybuffer
}
/*** server.js ***/
Files = new Mongo.Collection('files');
Meteor.methods({
'saveFile': function(buffer){
Files.insert({data:buffer})
}
});
外植
まず、ファイルはHTML5 File APIを使用して入力から取得されます。リーダーは、新しいFileReaderを使用して作成されます。ファイルはreadAsArrayBufferとして読み取られます。 console.logの場合、この配列バッファーは{}を返し、DDPはこれをネットワーク経由で送信できないため、Uint8Arrayに変換する必要があります。
これをMeteor.callに入れると、Meteorは自動的にEJSON.stringify(Uint8Array)を実行し、DDPで送信します。 chromeコンソールwebsocketトラフィックでデータを確認できます。base64に似た文字列が表示されます
サーバー側で、MeteorはEJSON.parse()を呼び出し、それをバッファに変換します
長所
短所
/*** client.js ***/
// asign a change event into input tag
'change input' : function(event,template){
var file = event.target.files[0];
if (!file) return;
var xhr = new XMLHttpRequest();
xhr.open('POST', '/uploadSomeWhere', true);
xhr.onload = function(event){...}
xhr.send(file);
}
/*** server.js ***/
var fs = Npm.require('fs');
//using interal webapp or iron:router
WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
//var start = Date.now()
var file = fs.createWriteStream('/path/to/dir/filename');
file.on('error',function(error){...});
file.on('finish',function(){
res.writeHead(...)
res.end(); //end the respone
//console.log('Finish uploading, time taken: ' + Date.now() - start);
});
req.pipe(file); //pipe the request to the file
});
説明
クライアント内のファイルが取得され、XHRオブジェクトが作成され、ファイルが「POST」経由でサーバーに送信されます。
サーバーでは、データは基礎となるファイルシステムにパイプされます。さらに、ファイル名を決定したり、サニタイズを実行したり、保存する前に既に存在するかどうかを確認したりできます。
長所
短所
/*** client.js ***/
//same as option 2
/*** version A: server.js ***/
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var GridStore = MongoInternals.NpmModule.GridStore;
WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
//var start = Date.now()
var file = new GridStore(db,'filename','w');
file.open(function(error,gs){
file.stream(true); //true will close the file automatically once piping finishes
file.on('error',function(e){...});
file.on('end',function(){
res.end(); //send end respone
//console.log('Finish uploading, time taken: ' + Date.now() - start);
});
req.pipe(file);
});
});
/*** version B: server.js ***/
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var GridStore = Npm.require('mongodb').GridStore; //also need to add Npm.depends({mongodb:'2.0.13'}) in package.js
WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
//var start = Date.now()
var file = new GridStore(db,'filename','w').stream(true); //start the stream
file.on('error',function(e){...});
file.on('end',function(){
res.end(); //send end respone
//console.log('Finish uploading, time taken: ' + Date.now() - start);
});
req.pipe(file);
});
説明
クライアントスクリプトは、オプション2と同じです。
Meteor 1.0.x mongo_driver.js last lineによると、MongoInternalsというグローバルオブジェクトが公開されているため、defaultRemoteCollectionDriver()を呼び出して、GridStoreに必要な現在のデータベースdbオブジェクトを返すことができます。バージョンAでは、GridStoreもMongoInternalsによって公開されます。現在の流星で使用されるmongoはv1.4.xです
その後、ルート内で、var file = new GridStore(...)( [〜#〜] api [〜#〜] )を呼び出して、新しい書き込みオブジェクトを作成できます。次に、ファイルを開いてストリームを作成します。
また、バージョンBも含めました。このバージョンでは、Npm.require( 'mongodb')を介して新しいmongodbドライブを使用してGridStoreが呼び出されます。このmongoは、このドキュメントの執筆時点で最新のv2.0.13です。新しい [〜#〜] api [〜#〜] では、ファイルを開く必要はありません。stream(true)を直接呼び出してパイピングを開始できます
長所
短所
Benchmarkオプション2およびオプション3で確認できます。varstart = Date.now()を含め、endを書き込むときにconsole.log time inms、以下が結果です。デュアルコア、4 GB RAM、HDD、ubuntu 14.04ベース。
file size GridFS FS
100 KB 50 2
1 MB 400 30
10 MB 3500 100
200 MB 80000 1240
FSはGridFSよりもはるかに高速です。200MBのファイルの場合、GridFSを使用すると約80秒かかりますが、FSでは約1秒しかかかりません。SSDを試したことはありません。ただし、実際には、帯域幅によってファイルがクライアントからサーバーにストリーミングされる速度が決まり、200 MB /秒の転送速度を達成することは一般的ではありません。 GridFS)はより一般的です。
結論
決して包括的なものではありませんが、ニーズに最適なオプションを決定できます。
うまくいけば、meteor DDPはgzip、キャッシングなどをサポートでき、GridFSはfaster...
こんにちは、ファイルの表示に関してOption1に追加するだけです。私はejsonなしでやった。
<template name='tryUpload'>
<p>Choose file to upload</p>
<input name="upload" class='fileupload' type='file'>
</template>
Template.tryUpload.events({
'change .fileupload':function(event,template){
console.log('change & view');
var f = event.target.files[0];//assuming upload 1 file only
if(!f) return;
var r = new FileReader();
r.onload=function(event){
var buffer = new Uint8Array(r.result);//convert to binary
for (var i = 0, strLen = r.length; i < strLen; i++){
buffer[i] = r.charCodeAt(i);
}
var toString = String.fromCharCode.apply(null, buffer );
console.log(toString);
//Meteor.call('saveFiles',buffer);
}
r.readAsArrayBuffer(f);};