問題

私はXHRを使ってファイルをサーバーに送信しようとしていましたが、ルーティングが不足しているためにエンドポイントがないことに気付きました。

次に、この記事を読み、Meteor.methodsを利用してファイルアップロードを行う可能性があることを発見しました。今私のアップロードは次のようになります:

 $(function() {
    $(document.body).html(Meteor.render(Template.files));
    $(document).on('drop', function(dropEvent) {
        _.each(dropEvent.originalEvent.dataTransfer.files, function(file) {
            var reader = new FileReader();
            reader.onload = function(fileLoadEvent) {
                Meteor.call('uploadFile', file, reader.result);
            };
            reader.readAsBinaryString(file);
        });
        dropEvent.preventDefault();
    });

    $(document).bind('dragover dragenter', function(e) {
        e.preventDefault();
    });

});
 

そして、server/main.jsで私はこれを持っています:

 var require = __meteor_bootstrap__.require; // should I even be doing this? looks like an internal method
var fs = require('fs');
var path = require('path');

Meteor.methods({
    uploadFile: function(fileInfo, fileData) {
        var fn = path.join('.uploads',fileInfo.name);
        fs.writeFile(fn, fileData, 'binary', function(err) {
            if(err) {
                throw new Meteor.Error(500, 'Failed to save file.', err);
            } else {
                console.log('File saved to '+fn);
            }
        });
    }
});
 

ディスクに書き込むだけです。これはうまくいくようですが、サーバー上のそのメソッドにデータを渡すためにMeteorがどのテクノロジーを使用しているのか分かりません。進捗情報を取得する方法はわかりません。

通常、イベントリスナーをxhrオブジェクトにアタッチします。

 xhr.upload.addEventListener("progress", uploadProgress, false);
 

しかし、私は.methodsで1つにアクセスできるとは思わない。これを行う別の方法はありますか?

  ベストアンサー

私はこれにも取り組んできました。動作するコードがいくつかあります。

最初に明確にするには:

これはうまくいくようですが、Meteorがサーバー上のそのメソッドにデータを渡すためにどのような技術を使用しているのか分かりません。進捗情報を取得する方法はわかりません。

Meteorは WebSockets 接続をサーバーと持ち、これをトランスポートとして使用します。したがって、 Meteor.call または Meteor.apply EJSON はパラメータをエンコードし、関数-serversideを呼び出し、透過的に応答を返します。

ここでのトリックは、 HTML5のFileReader Api を使用してファイルをチャンクで読み込み(大きなファイルがブラウザをクラッシュさせるため重要)、すべてのチャンクに対してMeteor.call()を実行することです。

あなたのコードは私にとってうまくいかなかった2つのことをしています:

  1. それはバイナリ文字列としてファイルを読んでいます:私はBase64を使用する方がはるかに信頼性が高いことがわかりました。あなたのコードがアップロードされていると言いますが、ファイルチェックサムをチェックして同じファイルであることを確認しましたか?
  2. それは一度にファイルをすべて読んでいます。大きなファイル(100MB)はパフォーマンスの問題を引き起こし、私の経験ではブラウザをクラッシュさせます。

さて、あなたの質問に。あなたがアップロードしたファイルの量を教えてください。チャンクを十分に小さくして、chunks_sent/total_chunksをメトリックとして使用できるようにすることができます。あるいは、Meteor server-side呼び出しからSession.set( 'progress'、current_size/total_size)を呼び

これは私がこの機能をラップするために取り組んできたjQueryプラグインです。それは完全ではありませんが、ファイルをアップロードし、あなたに役立つかもしれません。現在、ドラッグドロップを介してファイルを取得するだけです。「ブラウズ」ボタンはありません。

免責事項:Meteor&を初めて使用しています。ノード、したがって、「推奨」な方法ではできないことがありますが、時間の経過とともに改善し、最終的にGithubに家を与えます。

 ;(function($) {

    $.uploadWidget = function(el, options) {

        var defaults = {
            propertyName: 'value',
            maximumFileSize: 1073741824, //1GB

            messageTarget: null
        };

        var plugin = this;

        plugin.settings = {}


        var init = function() {
            plugin.settings = $.extend({}, defaults, options);
            plugin.el = el;

            if( !$(el).attr('id') || !$(el).attr('id').length ){
                $(el).attr('id', 'uploadWidget_' + Math.round(Math.random()*1000000));
            }

            if( plugin.settings.messageTarget == null ){
                plugin.settings.messageTarget = plugin.el;
            }

            initializeDropArea();
        };


        // Returns a human-friendly string representation of bytes
        var getBytesAsPrettyString = function( bytes ){

            var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
            if (bytes == 0) return 'n/a';
            var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
            return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];

        };


        // Throws an exception if the file (from a drop event) is unacceptable
        var assertFileIsAcceptable = function( file ){

            if( file.size > plugin.settings.maximumFileSize ){
                throw 'Files can\'t be larger than ' + getBytesAsPrettyString(plugin.settings.maximumFileSize);
            }

            //if( !file.name.match(/^.+?\.pdf$/i) ){
            //    throw 'Only pdf files can be uploaded.';
            // }

        };


        var setMainMessage = function( message ){

            $(plugin.settings.messageTarget).text( message );

        };


        plugin.getUploader = function(){

            return plugin.uploader;

        };


        var initializeDropArea = function(){

            var $el = $(plugin.el);

            $.event.props.push("dataTransfer");

            $el.bind( 'dragenter dragover dragexit', function(){
                event.stopPropagation();
                event.preventDefault();
            });

            $el.bind( 'drop', function( event ){

                var slices;
                var total_slices;

                var processChunkUpload = function( blob, index, start, end ){

                    var chunk;

                    if (blob.webkitSlice) {
                        chunk = blob.webkitSlice(start, end);
                    } else if (blob.mozSlice) {
                        chunk = blob.mozSlice(start, end);
                    } else {
                        chunk = blob.slice(start,end);
                    }

                    var reader = new FileReader();

                    reader.onload = function(event){

                        var base64_chunk = event.target.result.split(',')[1];

                        slices--;

                        $el.text( slices + ' out of ' + total_slices + ' left' );

                        Meteor.apply(
                            'saveUploadFileChunk',
                            [file_name, base64_chunk, slices+1],
                            { wait: true }
                        );
                    };

                    reader.readAsDataURL(chunk);
                };


                event.stopPropagation();
                event.preventDefault();
                event.dataTransfer.dropEffect = 'copy';

                if( !event.dataTransfer.files.length ){
                    return;
                }

                const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.


                var blob = event.dataTransfer.files[0];
                var file_name = blob.name;

                var start = 0;
                var end;
                var index = 0;

                // calculate the number of slices we will need
                slices = Math.ceil(blob.size / BYTES_PER_CHUNK);
                total_slices = slices;

                while(start < blob.size) {
                    end = start + BYTES_PER_CHUNK;
                    if(end > blob.size) {
                        end = blob.size;
                    }

                    processChunkUpload( blob, index, start, end );

                    start = end;
                    index++;
                }


            });

        };

        init();

    }

})(jQuery);
 

これは私の流星出版の方法です。

 Meteor.methods({

        // this is TOTALLY insecure. For demo purposes only.
        // please note that it will append to an existing file if you upload a file by the same name..
        saveUploadFileChunk: function ( file_name, chunk, chunk_num ) {

                var require = __meteor_bootstrap__.require;
                var fs = require('fs');
                var crypto = require('crypto')

                var shasum = crypto.createHash('sha256');
                shasum.update( file_name );

                var write_file_name = shasum.digest('hex');

                var target_file = '../tmp/' + write_file_name;

                fs.appendFile(
                        target_file,
                        new Buffer(chunk, 'base64'),
                        {
                                encoding: 'base64',
                                mode: 438,
                                flag: 'a'
                        }
                        ,function( err ){

                                if( err ){

                                        console.log('error ' + err);
                                }

                                console.log( 'wrote ' + chunk_num );

                        }
                );

                return write_file_name;

        }
});
 

HTH

  同じタグがついた質問を見る

meteor