我正在构建一个文件上传组件,该组件允许您暂停/恢复文件上传。
实现此目的的标准方法似乎是在客户端计算机上将文件分解成多个块,然后将这些块连同簿记信息一起发送到服务器,该服务器可以将这些块存储到暂存目录中,然后在将其合并时将它们合并在一起已收到所有块。所以,这就是我正在做的。
我正在使用node / express,并且能够很好地处理文件,但是由于merge_chunks
多次调用我的函数,因此遇到了问题。
这是我的调用堆栈:
router.post('/api/videos',
upload.single('file'),
validate_params,
rename_uploaded_chunk,
check_completion_status,
merge_chunks,
record_upload_date,
videos.update,
send_completion_notice
);
该check_completion_status
功能实现如下:
/* Recursively check to see if we have every chunk of a file */
var check_completion_status = function (req, res, next) {
var current_chunk = 1;
var see_if_chunks_exist = function () {
fs.exists(get_chunk_file_name(current_chunk, req.file_id), function (exists) {
if (current_chunk > req.total_chunks) {
next();
} else if (exists) {
current_chunk ++;
see_if_chunks_exist();
} else {
res.sendStatus(202);
}
});
};
see_if_chunks_exist();
};
登台目录中的文件名中嵌入了块号,因此,其目的是查看是否每个块号都有一个文件。next()
对于给定的(完整)文件,该功能应该只有一次。
但是,我的merge_chunks
函数被多次调用。(通常在1到4之间),日志记录确实显示出只有在我收到所有块之后才调用它。
考虑到这一点,我在这里的假设是fs.exists
引起问题的是函数的异步特性。
即使n
'的第一个调用check_completion_status
可能在我拥有所有块之前发生,但到我们进行n
第to次调用时fs.exists()
,x
可能已经到达并同时处理了更多的块,因此该功能可以继续进行,在某些情况下可以最后和next()
。但是,同时到达的那些块也将与的调用相对应check_completion_status
,这也将与之对应,next()
因为此时我们显然已经拥有所有文件。
这引起了问题,因为我写的时候没有考虑这个问题merge_chunks
。
为了完整起见,以下是merge_chunks
函数:
var merge_chunks = (function () {
var pipe_chunks = function (args) {
args.chunk_number = args.chunk_number || 1;
if (args.chunk_number > args.total_chunks) {
args.write_stream.end();
args.next();
} else {
var file_name = get_chunk_file_name(args.chunk_number, args.file_id)
var read_stream = fs.createReadStream(file_name);
read_stream.pipe(args.write_stream, {end: false});
read_stream.on('end', function () {
//once we're done with the chunk we can delete it and move on to the next one.
fs.unlink(file_name);
args.chunk_number += 1;
pipe_chunks(args);
});
}
};
return function (req, res, next) {
var out = path.resolve('videos', req.video_id);
var write_stream = fs.createWriteStream(out);
pipe_chunks({
write_stream: write_stream,
file_id: req.file_id,
total_chunks: req.total_chunks,
next: next
});
};
}());
当前,我收到一个错误消息,因为该函数的第二次调用正在尝试读取已被第一次调用删除的块。
处理此类情况的典型模式是什么?如果可能的话,我想避免使用有状态的架构。是否可以在调用next()
check_completion_status之前立即取消挂起的处理程序?
如果您只是想使其尽快运行,我将使用一个锁(非常类似于db锁)来锁定资源,以便只有一个请求可以处理这些块。只需在客户端上创建一个唯一的ID,然后将其与数据块一起发送即可。然后,只需将该唯一ID存储在某种数据结构中,然后在处理之前查找该ID。下面的示例到目前为止还不是最佳示例(实际上,此地图将继续增长,这很糟糕),但它应演示该概念
// Create a map (an array would work too) and keep track of the video ids that were processed. This map will persist through each request.
var processedVideos = {};
var check_completion_status = function (req, res, next) {
var current_chunk = 1;
var see_if_chunks_exist = function () {
fs.exists(get_chunk_file_name(current_chunk, req.file_id), function (exists) {
if (processedVideos[req.query.uniqueVideoId]){
res.sendStatus(202);
} else if (current_chunk > req.total_chunks) {
processedVideos[req.query.uniqueVideoId] = true;
next();
} else if (exists) {
current_chunk ++;
see_if_chunks_exist();
} else {
res.sendStatus(202);
}
});
};
see_if_chunks_exist();
};
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句