You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 19:06:06