Flask后端无法上传BAM文件:Argument must be string, bytes or unicode错误排查求助
Flask后端无法上传BAM文件:Argument must be string, bytes or unicode错误排查求助
我刚仔细看了你的代码,确实能发现几个可能导致最后一块上传失败、以及出现类型错误的问题,尤其是分块合并和文件对象/路径混用的部分,咱们一步步来理清楚:
1. 最可能触发"Argument must be string..."错误的核心问题:文件对象 vs 文件路径混淆
在你的Flask代码里,合并完完整文件后的函数调用存在明显的类型错误:
with open(complete_file_path, 'wb') as output_file: # ...分块合并代码... if rcg.is_valid_bam(output_file): # 这里传的是已打开的文件对象而非路径! sorted_bam = rcg.sort_and_index_bam(output_file) else: coverage = rcg.calculate_full_coverage(output_file, mode)
output_file是一个已打开的文件句柄,但rcg.is_valid_bam这类工具函数大概率需要的是文件路径字符串(比如complete_file_path),而非打开的文件对象。把文件句柄传入时,函数内部会因类型不匹配抛出"Argument must be string, bytes or unicode"错误,这应该是你看到500错误的直接原因。
修复方案:
将所有需要文件路径的调用,替换为complete_file_path,并确保文件在调用前已关闭(with语句块结束后会自动关闭文件):
# 分块合并完成后,output_file已自动关闭 complete_file_path = os.path.join(UPLOAD_DIR, file_name) with open(complete_file_path, 'wb') as output_file: for i in range(total_chunks): part_path = os.path.join(UPLOAD_DIR, f"{file_name}.part{i}") with open(part_path, 'rb') as part_file: output_file.write(part_file.read()) os.remove(part_path) # 传入文件路径而非文件对象调用工具函数 if rcg.is_valid_bam(complete_file_path): sorted_bam = rcg.sort_and_index_bam(complete_file_path) coverage = rcg.calculate_full_coverage(sorted_bam, mode) else: coverage = rcg.calculate_full_coverage(complete_file_path, mode)
2. 分块上传的并发与判断逻辑漏洞
你前端同步发起所有分块的fetch请求,可能导致:
- 服务器同时处理多个文件写入,最后一个chunk的文件还未完全保存到磁盘,后端就开始执行合并逻辑,读取到不完整的chunk文件
- 分块数量判断不准确:
len(uploaded_chunks) == total_chunks用startswith(file_name)匹配,若存在同名文件(如test.bam和test.bam.old)会误判分块数量,提前触发合并
修复方案:
后端:精确匹配分块文件
修改分块判断逻辑,避免误匹配:
# 原来的模糊匹配 # uploaded_chunks = [f for f in os.listdir(UPLOAD_DIR) if f.startswith(file_name)] # 改成精确匹配分块文件名 expected_chunk_names = {f"{file_name}.part{i}" for i in range(total_chunks)} uploaded_chunks = [f for f in os.listdir(UPLOAD_DIR) if f in expected_chunk_names] if len(uploaded_chunks) == total_chunks: # 执行合并逻辑
前端:控制分块上传并发数,避免同时发起所有请求
将同步循环改为串行上传(或限制并发数),降低服务器压力:
// 先修复函数参数不匹配的问题:原来调用传3个参数,但定义只接1个 async function file_to_readdata(uploadedFile, mode, fileType) { const chunkSize = 10 * 1024 * 1024; // 10MB块 const totalChunks = Math.ceil(uploadedFile.size / chunkSize); let uploadedChunks = 0; // 串行上传:完成一块再传下一块 for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize, uploadedFile.size); const chunk = uploadedFile.slice(start, end); console.log(`Uploading chunk ${i + 1}/${totalChunks}`); console.log("Chunk size:", chunk.size); const formData = new FormData(); formData.append("chunk", chunk); formData.append("chunkIndex", i); formData.append("totalChunks", totalChunks); formData.append("fileName", uploadedFile.name); formData.append("mode", mode); // 新增:把mode传给后端 try { const response = await fetch(`${$SCRIPT_ROOT}/_upload_file`, { method: "POST", body: formData, }); const data = await response.json(); console.log(data); if (data.status === "success") { uploadedChunks++; if (uploadedChunks === totalChunks) { console.log("File upload complete"); // 可添加前端成功提示 } } else { console.error(`Error uploading chunk ${i + 1}:`, data.message); break; } } catch (error) { console.error(`Error uploading chunk ${i + 1}:`, error); break; } } }
3. 其他潜在问题
- 参数传递缺失:前端原代码未将
mode传入后端,导致request.form.get('mode')为None,可能触发后续计算逻辑错误(已在前端修复中补充) - 分块文件残留:若合并失败,分块文件会残留,可在
except块中添加清理逻辑,删除已上传的分块文件 - 文件权限:确保
UPLOAD_DIR目录有足够的读写权限,避免分块保存或合并时出现权限错误
总结
最紧急的是修复文件对象误传为路径的问题,这直接触发了你看到的类型错误;其次控制前端上传并发数,避免服务器压力过载;最后修复参数传递和分块判断逻辑,应该就能解决最后一块上传失败的问题了。你可以先尝试这些修复,有新的错误信息或问题再反馈!
备注:内容来源于stack exchange,提问作者Ivar2001
相关产品推荐
相关产品推荐

