React向Flask传递PDF时出现BadRequestKeyError问题排查
排查React fetch传PDF到Flask时的KeyError: 'file'问题及优化方案
问题原因分析
虽然后端能保存文件,但抛出KeyError: 'file',核心原因是前端传递的FormData键名与后端期望的'file'不匹配,或是请求头设置错误导致后端无法正确解析表单数据。常见触发场景:
- 前端FormData添加文件时用了其他键名(比如'pdf'),但后端用
request.files['file']获取 - 手动设置了
Content-Type: multipart/form-data请求头,导致浏览器无法自动生成正确的boundary分隔符,后端解析失败 - 前端未正确将文件对象添加到FormData中
代码修正示例
React前端修正
确保FormData的键名是'file',且不手动设置Content-Type(让浏览器自动处理多表单数据的边界符):
const handleSubmit = async (e) => { e.preventDefault(); if (!selectedFile) return; const formData = new FormData(); // 键名必须和后端request.files['file']的键完全一致 formData.append('file', selectedFile); try { const response = await fetch('/api/upload-pdf', { method: 'POST', body: formData // 不要手动设置Content-Type,浏览器会自动添加带boundary的正确头 }); if (!response.ok) throw new Error('请求失败'); const result = await response.json(); console.log('处理结果:', result); } catch (error) { console.error('上传失败:', error); } };
Flask后端修正
先校验请求中是否存在目标文件,再执行后续逻辑,同时添加基础的文件校验:
from flask import Flask, request, jsonify from werkzeug.utils import secure_filename import os app = Flask(__name__) UPLOAD_FOLDER = './uploads' os.makedirs(UPLOAD_FOLDER, exist_ok=True) # 限制上传文件大小为10MB app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024 @app.route('/api/upload-pdf', methods=['POST']) def upload_pdf(): # 先检查请求中是否包含'file'字段 if 'file' not in request.files: return jsonify({'error': '未上传任何文件'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'error': '未选择文件'}), 400 # 校验文件类型 if not file.filename.lower().endswith('.pdf'): return jsonify({'error': '仅支持PDF格式文件'}), 400 # 用secure_filename处理文件名,避免路径遍历攻击 safe_filename = secure_filename(file.filename) file_path = os.path.join(UPLOAD_FOLDER, safe_filename) file.save(file_path) # 执行PDF解析逻辑(示例函数,需根据实际需求实现) parsed_data = parse_pdf_content(file_path) return jsonify({'data': parsed_data}), 200 def parse_pdf_content(file_path): # 示例解析逻辑,可替换为PyPDF2、pdfplumber等库的实际解析代码 return { 'filename': os.path.basename(file_path), 'pages': 3, 'content': '提取的PDF文本内容示例' } # 捕获文件过大的异常 @app.errorhandler(413) def request_entity_too_large(error): return jsonify({'error': '文件大小超过限制(最大10MB)'}), 413 if __name__ == '__main__': app.run(debug=True)
更优实现方式
前端侧增强
- 添加文件大小、类型的前置校验,提前拦截不符合要求的文件
- 实现上传进度显示:利用
fetch结合ReadableStream监听上传进度,给用户直观反馈 - 完善错误处理:区分网络错误、后端返回的业务错误(如文件过大、格式不符),给出对应提示
后端侧增强
- 异步处理PDF解析:如果解析耗时较长,用Celery等异步任务队列,避免阻塞HTTP请求,返回任务ID让前端轮询结果
- 添加日志记录:记录上传文件的名称、大小、处理状态、错误信息,方便后续排查问题
- 定期清理上传文件:设置定时任务,清理超过保留期限的临时PDF文件,避免磁盘空间占用过多
内容的提问来源于stack exchange,提问作者Yehuda
相关产品推荐
相关产品推荐

