我终于找到了我的主要问题的答案:
在上传完成后和调用我的操作之前的这 3 分钟等待期间发生了什么?
这一切都在这篇文章中解释得很清楚:
Rails Way - Uploading Files
“当浏览器上传文件时,它会将内容编码为一种称为‘multipart mime’的格式(它与您发送电子邮件附件时使用的格式相同)。为了让您的应用程序对该文件执行某些操作,rails 有撤消这种编码。要做到这一点,需要读取巨大的请求正文,并将每一行与几个正则表达式进行匹配。这可能非常慢,并且会占用大量的 CPU 和内存。
我尝试了帖子中提到的modporter Apache 模块。唯一的问题是该模块及其相应的插件是 4 年前编写的,并且他们的网站不再运行,几乎没有任何一个文档。
使用modporter时,我想将我的 NFS 挂载目录指定为 PorterDir,希望它将文件直接传递到 NAS,而无需从临时目录进行任何额外的复制。但是,我无法做到这一点,因为该模块似乎忽略了我指定的 PorterDir,并且正在返回一条完全不同的路径来执行我的操作。最重要的是,它返回的路径甚至都不存在,所以我不知道我的上传实际发生了什么。
我的解决方法
我必须快速解决问题,所以我现在采用了一个有点老套的解决方案,其中包括编写相应的 JavaScript/Ruby 代码来处理分块文件上传。
JS 示例:
var MAX_CHUNK_SIZE = 20000000; // in bytes
window.FileUploader = function (opts) {
var file = opts.file;
var url = opts.url;
var current_byte = 0;
var success_callback = opts.success;
var progress_callback = opts.progress;
var percent_complete = 0;
this.start = this.resume = function () {
paused = false;
upload();
};
this.pause = function () {
paused = true;
};
function upload() {
var chunk = file.slice(current_byte, current_byte + MAX_CHUNK_SIZE);
var fd = new FormData();
fd.append('chunk', chunk);
fd.append('filename', file.name);
fd.append('total_size', file.size);
fd.append('start_byte', current_byte);
$.ajax(url, {
type: 'post',
data: fd,
success: function (data) {
current_byte = data.next_byte;
upload_id = data.upload_id;
if (data.path) {
success_callback(data.path);
}
else {
percent_complete= Math.round(current_byte / file.size * 100);
if (percent_complete> 100) percent_complete = 100;
progress_callback(percent_complete); // update some UI element to provide feedback to user
upload();
}
}
});
}
};
(请原谅任何语法错误,只是在我脑海中输入这个)
在服务器端,我创建了一个新路由来接受文件块。在第一次提交块时,我根据文件名/大小生成一个 upload_id,并确定我是否已经有来自中断上传的部分文件。如果是这样,我将我需要的下一个起始字节与 id 一起传回。如果没有,我存储第一个块并传回 id。
附加块上传的过程会附加部分文件,直到文件大小与原始文件大小匹配。此时,服务器以文件的临时路径进行响应。
然后,javascript 从表单中删除文件输入,并将其替换为隐藏输入,其值为从服务器返回的文件路径,然后发布表单。
最后在服务器端,我处理移动/重命名文件并将其最终路径保存到我的模型。
呸。