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

React Native调用Heroku端FastAPI文件上传接口报400错误解决方法

问题描述

实现文件上传功能,将文件作为入参传递给FastAPI后端处理时,Swagger内接口测试可正常运行,但从React Native手机端调用部署在Heroku上的对应接口始终失败,返回400 Bad Request错误。首次接触API开发,无法确认请求体参数格式、接口调用方式是否正确,需要明确接收文件类型入参的API的正确调用方法。

相关参考截图

现有代码

React Native端代码

const getImg = async imageUrl => {
    const response = await fetch(imageUrl);
    const imageBlob = await response.blob();
    const reader = new FileReader();
    reader.readAsDataURL(imageBlob);
    reader.onloadend = () => {
      const base64data = reader.result;
      setImgUrl(base64data);
    };
  };
const chooseFromLibrary = () => {
    ImagePicker.openPicker({
      width: 300,
      height: 400,
      cropping: false,
    }).then(image => {
      console.log(image);
      console.log(image['mime']);
      getImg(image.path);
      hi();
    });
  };
const hi = async () => {
    let response = await fetch(
      'https://receipt-ocr-heroku.herokuapp.com/receiptOcr',
      {
        method: 'POST',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'multipart/form-data',
        },
        body: JSON.stringify({
          file: imgUrl,
        }),
      },
    );
    console.log(response);
    let result = await response.json();
    console.log(result);
  };

FastAPI端代码

@app.post("/receiptOcr")
async def main(file: UploadFile = File(...)):
    try:
        image = await file.read()
        # image = cv2.imread(image)
        nparr = np.fromstring(image, np.uint8)
        img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
错误原因

现有代码存在3个直接导致400错误的问题:

  1. 异步时序错误:getImg是异步读取文件的操作,调用后立刻执行hi()发起请求时,base64格式的imgUrl还未完成赋值,实际传参为空。
  2. 请求格式错误:multipart/form-data类型请求不能用JSON.stringify包裹请求体,手动固定设置Content-Type: multipart/form-data会导致fetch无法自动生成携带随机boundary分隔符的合法请求头,FastAPI无法解析请求体。
  3. 参数格式错误:FastAPI的UploadFile类型要求接收标准multipart格式的文件流,而非base64字符串,将文件转base64后塞入JSON结构完全不符合接口入参要求。
修复方案
  1. 删除多余的base64转换逻辑,直接使用标准FormData对象构造上传参数,不需要额外转码。
  2. 移除手动设置的Content-Type请求头,由fetch自动生成携带正确boundary的请求头。
  3. 修正异步时序逻辑,选完图片后直接构造参数发起请求,避免异步赋值导致的参数为空问题。

修正后的React Native上传代码如下:

const chooseFromLibrary = () => {
  ImagePicker.openPicker({
    width: 300,
    height: 400,
    cropping: false,
  }).then(async (image) => {
    // 构造multipart上传表单
    const formData = new FormData();
    // 字段名必须和FastAPI接口的参数名`file`完全一致
    formData.append('file', {
      uri: image.path,
      type: image.mime,
      name: image.filename || 'receipt.jpg'
    });

    try {
      const response = await fetch(
        'https://receipt-ocr-heroku.herokuapp.com/receiptOcr',
        {
          method: 'POST',
          headers: {
            Accept: 'application/json'
            // 不要手动设置Content-Type,否则会丢失boundary标识
          },
          body: formData
        }
      );
      const result = await response.json();
      console.log('接口返回结果', result);
    } catch (err) {
      console.log('上传请求异常', err);
    }
  });
};
  • 注意事项:FastAPI端UploadFile参数默认匹配和参数名完全一致的表单字段,这里后端参数名为file,FormData追加字段的key必须是file,大小写完全匹配才能被正确识别。Heroku免费版对单请求体大小限制为30MB,上传时注意文件大小不要超限。
  • 额外提示:FastAPI端使用的np.fromstring方法在numpy新版本中已被弃用,建议替换为np.frombuffer避免后续运行警告。

内容的提问来源于stack exchange,提问作者random

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:42:16