为何HTTP请求将图片文件存入request.form而非request.files?
问题描述
使用Flask搭建API处理React Native和单元测试的图片上传POST请求时,出现异常:图片数据未被存入request.files,反而以字符串形式出现在request.form中。具体表现:
request.files返回<ImmutableMultiDict([])>(空字典)request.form['image']返回字符串<FileStorage: 'test.jpg' ('image/jpeg')>,而非实际的FileStorage对象
相关代码
单元测试代码(unit_test.py)
import io import unittest from api import app class FlaskAppTests(unittest.TestCase): def setUp(self): self.app = app.test_client() self.app.testing = True with open('image/test.jpg', 'rb') as img: self.binary_image = img.read() def test_facial_authentication_response(self): response = self.app.post('/facial_authentication', content_type='multipart/form-data', data={ 'image': (self.binary_image, 'test.jpg', 'image/jpeg') }) self.assertEqual(response.status_code, 200) self.assertEqual(response.content_type, 'application/json') if __name__ == '__main__': unittest.main()
React Native代码
await fetch('http://api-end-point', { method: 'POST', headers: {'Content-Type': 'multipart/form-data'}, body: formData, }).then(res => res.json()).then(json => { console.log(json); }).catch((error) => { console.error(error); });
Flask后端代码(app.py)
import io from flask import Flask, request app = Flask(__name__) CORS(app) @app.route('/', methods=['POST']) def api(): image_from_form = request.files['image'] # 报错,因为字典为空 image_from_files = request.form['image'] # 返回字符串"<FileStorage: 'test.jpg' ('image/jpeg')>" print(image_from_form, " and ", image_from_files) # 输出:ImmutableMultiDict([]) and ImmutableMultiDict([('image', "<FileStorage: 'test.jpg' ('image/jpeg')>")]) with open(os.path.join(dirname, 'temp.jpg'), "wb") as file: file.write(binary_image)
解决方案
1. 修复单元测试代码
Flask test_client解析multipart文件时,需要传递文件对象(如io.BytesIO或打开的文件句柄)而非原始二进制数据。修改后代码:
import io import unittest from api import app class FlaskAppTests(unittest.TestCase): def setUp(self): self.app = app.test_client() self.app.testing = True with open('image/test.jpg', 'rb') as img: # 用BytesIO包装二进制数据,模拟文件对象 self.image_io = io.BytesIO(img.read()) def test_facial_authentication_response(self): response = self.app.post('/facial_authentication', content_type='multipart/form-data', data={ 'image': (self.image_io, 'test.jpg', 'image/jpeg') }) self.assertEqual(response.status_code, 200) self.assertEqual(response.content_type, 'application/json') if __name__ == '__main__': unittest.main()
2. 修复React Native代码
不要手动设置Content-Type: multipart/form-data,因为FormData会自动生成包含boundary的正确Content-Type,手动设置会导致Flask无法解析文件字段:
await fetch('http://api-end-point', { method: 'POST', // 移除手动设置的Content-Type头 body: formData, }).then(res => res.json()).then(json => { console.log(json); }).catch((error) => { console.error(error); });
3. 修复Flask后端代码
统一路由路径(与单元测试请求的/facial_authentication匹配),并正确从request.files获取FileStorage对象:
import os from flask import Flask, request from flask_cors import CORS app = Flask(__name__) CORS(app) @app.route('/facial_authentication', methods=['POST']) def facial_authentication(): # 安全获取文件对象,避免KeyError image_file = request.files.get('image') if not image_file: return {"error": "未提供图片文件"}, 400 # 保存文件到指定路径 save_dir = os.path.dirname(__file__) save_path = os.path.join(save_dir, 'temp.jpg') image_file.save(save_path) return {"status": "success", "message": "图片已保存"}, 200 if __name__ == '__main__': app.run(debug=True)
问题原因说明
- 单元测试中传递原始二进制数据时,Flask无法将其识别为文件,只能以字符串形式存入
request.form;使用文件对象(如BytesIO)才能触发Flask的multipart文件解析逻辑。 - React Native手动设置
Content-Type会丢失multipart表单必需的boundary标识,导致Flask无法区分表单中的字段类型,进而无法将文件存入request.files。
内容的提问来源于stack exchange,提问作者KPB98115
相关产品推荐
相关产品推荐

