Flask跨服务器传文件时接收端request.files为空的问题
Flask服务器间文件传输:request.files为空触发KeyError问题
问题场景
在两台Flask服务器(Server 1与Server 2)间双向传输文件时,Server 1能正常接收文件,但将文件转发至Server 2后,Server 2的request.files对象为空,访问request.files['file']时触发KeyError。
服务器代码
Server 1 原代码
from flask import Flask, request import requests app = Flask(__name__) @app.route('/test', methods=['POST']) def test(): file = request.files['file'].read() print(file) response = requests.post(url="http://127.0.0.1:5002/test", headers=request.headers, files={'file': file} ) return response.json(), response.status_code if __name__ == "__main__": app.run(port=5000)
Server 2 原代码
from flask import Flask, request app = Flask(__name__) @app.route('/test', methods=["POST"]) def test(): file = request.files['file'] # <-- 此处触发KeyError print(file) return 1, 200 if __name__ == "__main__": app.run(port=5002, debug=True)
报错信息
127.0.0.1 - - [23/Mar/2024 10:09:02] "POST /test HTTP/1.1" 500 - Traceback (most recent call last): File "C:\Users\gratu\anaconda3\envs\ML\lib\site-packages\flask\app.py", line 1488, in __call__ return self.wsgi_app(environ, start_response) File "C:\Users\gratu\anaconda3\envs\ML\lib\site-packages\flask\app.py", line 1466, in wsgi_app response = self.handle_exception(e) File "C:\Users\gratu\anaconda3\envs\ML\lib\site-packages\flask\app.py", line 1463, in wsgi_app response = self.full_dispatch_request() File "C:\Users\gratu\anaconda3\envs\ML\lib\site-packages\flask\app.py", line 872, in full_dispatch_request rv = self.handle_user_exception(e) File "C:\Users\gratu\anaconda3\envs\ML\lib\site-packages\flask\app.py", line 870, in full_dispatch_request rv = self.dispatch_request() File "C:\Users\gratu\anaconda3\envs\ML\lib\site-packages\flask\app.py", line 855, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] File "C:\Users\gratu\Projects\flasktest\app2.py", line 10, in test file = request.files['file'] File "C:\Users\gratu\anaconda3\envs\ML\lib\site-packages\werkzeug\datastructures\structures.py", line 192, in __getitem__ raise exceptions.BadRequestKeyError(key) werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. KeyError: 'file'
问题原因与解决思路
核心问题点
- 文件传递格式错误:Server 1中调用
request.files['file'].read()后,传递给requests.post的是字节流,而files参数需要的是文件对象或包含文件名、文件对象、MIME类型的元组,直接传字节流会导致Server 2无法解析为文件。 - 头部冲突:直接传递
request.headers会覆盖requests自动生成的multipart/form-data头部(包含boundary分隔符),导致Server 2无法识别请求中的文件部分,最终request.files为空。
修改后的Server 1代码
from flask import Flask, request import requests app = Flask(__name__) @app.route('/test', methods=['POST']) def test(): # 获取原始文件对象,避免直接读取字节流 file_obj = request.files['file'] # 读取文件内容后重置指针,确保转发时能重新读取 print(file_obj.read()) file_obj.seek(0) # 转发时使用正确的files格式,不手动传递headers response = requests.post( url="http://127.0.0.1:5002/test", files={'file': (file_obj.filename, file_obj, file_obj.content_type)} ) return response.json(), response.status_code if __name__ == "__main__": app.run(port=5000)
优化后的Server 2代码(增加异常处理)
from flask import Flask, request, abort app = Flask(__name__) @app.route('/test', methods=["POST"]) def test(): # 先检查是否存在文件部分 if 'file' not in request.files: abort(400, description="No file part in request") file = request.files['file'] # 检查是否选择了文件 if file.filename == '': abort(400, description="No file selected") print(file.read()) return {"status": "success"}, 200 if __name__ == "__main__": app.run(port=5002, debug=True)
关键说明
- 使用
file_obj.seek(0):因为调用read()后文件指针会移动到末尾,重置指针才能让转发时正确读取文件内容。 - 不传递自定义headers:
requests在发送multipart/form-data请求时会自动生成包含boundary的Content-Type头部,手动传递原头部会破坏这一机制,导致Server 2无法解析文件。 - 正确的
files参数格式:元组(文件名, 文件对象, 内容类型)能让Server 2正确识别并解析文件。
内容的提问来源于stack exchange,提问作者Richard AR
相关产品推荐
相关产品推荐

