gpt4 book ai didi

meteor - 使用 Meteor 获取上传进度

转载 作者:行者123 更新时间:2023-12-02 11:39:04 25 4
gpt4 key购买 nike

当我意识到由于缺乏路由而没有端点时,我正打算使用 XHR 向服务器发送文件。

然后我读到 this article并发现我可以利用 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 访问该方法。还有其他方法可以做到这一点吗?

最佳答案

我也一直在研究这个问题,并且我有一些有效的代码。

首先澄清一下:

This seems to work, but I don't know what technology Meteor is using to pass the data to that method on the server, and I don't know how to get progress info back.

meteor 有一个 WebSockets与服务器的连接,并将其用作传输。所以每次你调用 Meteor.callMeteor.apply它将 EJSON对您的参数(如果有)进行编码,调用服务器端的函数,并透明地返回响应。

这里的技巧是使用 HTML5's FileReader Api分块读取文件(很重要,否则大文件会使浏览器崩溃)并对每个 block 执行 Meteor.call() 。

您的代码做了两件事,但对我来说效果不佳:

  1. 它将文件作为二进制字符串读取:我发现使用 Base64 更可靠。您说您的代码已上传,但您是否检查过文件校验和以确保它们是同一文件?
  2. 它正在一次读取所有文件。大文件(数百 MB)会导致性能问题,根据我的经验,甚至会导致浏览器崩溃。

好的,现在回答你的问题。如何知道您上传了多少文件?您可以使 block 足够小,以便可以使用 chunks_sent/total_chunks 作为衡量标准。 或者,您可以从 Meteor 服务器端调用中调用 Session.set( 'progress', current_size/total_size ) 并将其绑定(bind)到一个元素以使其更新。

这是一个 jQuery 插件,我一直致力于封装此功能。它并不完整,但它可以上传文件,可能对您有帮助。目前它只能通过拖放获取文件。没有“浏览”按钮。

免责声明:我对 Meteor 和 Node 还很陌生,所以有些事情可能不会按照“推荐”的方式完成,但我会随着时间的推移改进它,并最终在 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 发布方法。

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 - 使用 Meteor 获取上传进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14805770/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com