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

如何创建form-data文件类型Body的JavaScript Request对象

问题根因

文件上传失败的核心原因是你手动给FormData请求设置了错误的Content-Type请求头。
当请求体为FormData类型时,浏览器会自动生成携带正确boundary边界参数的multipart/form-data类型Content-Type头,这是后端解析表单文件的必要标识。你手动传入application/vnd.ms-excel作为Content-Type,会导致后端无法按照表单格式解析请求体,Flask自然无法从request.files中读取到上传的文件。
另外你当前封装的方法存在两个小问题:一是isBlobRequest字段未从配置参数中解构,会导致判断逻辑失效;二是RxJS的Observable是冷执行的,不调用subscribe不会真正发起请求。

修复步骤

1. 改造通用请求封装方法

将contentType参数改为可选,新增FormData类型判断逻辑:当请求体是FormData实例时,跳过手动设置Content-Type的步骤,交给浏览器自动生成合法的请求头。修正后的封装代码如下:

import { fromFetch } from 'rxjs/fetch';
import { switchMap } from 'rxjs/operators';

interface FetchRequest<TBody> {
  method?: FetchMethod;
  body?: TBody;
  headers?: FetchHeaders;
  isBlobRequest?: boolean;
}

export const request = <TBody extends BodyInit = BodyInit>(
  url: string,
  fetchRequest?: FetchRequest<TBody>,
  contentType?: string
) => {
  // 补充解构isBlobRequest配置
  const { method = 'POST', body, headers, isBlobRequest = false } = fetchRequest ?? {};
  const { dispatch } = createStore();

  const customHeaders: Record<string, string> = { ...headers };
  // 非FormData请求才手动设置Content-Type
  if (!(body instanceof FormData) && contentType) {
    customHeaders['Content-Type'] = contentType;
  }

  const req = new Request(`${domainUrl}${url}`, {
    method,
    body: body ?? null,
    headers: customHeaders,
    credentials: 'include',
  });
  
  return fromFetch(req).pipe(
    switchMap((response: Response) => {
      if (response.status === SUCCESS_CODE) {
        return isBlobRequest ? response.blob() : response.text();
      } else if (response.status === USER_SESSION_EXPIRED_CODE) {
        dispatch(authAsyncActions.setSessionExpired());
        throw response;
      } else {
        throw response;
      }
    })
  );
};

2. 修正文件上传调用逻辑

上传文件时不需要手动传入Content-Type参数,FormData.append方法直接传入File实例即可,浏览器会自动识别文件类型、填充文件名等元信息。注意要订阅返回的Observable才能真正发起请求:

const callUploadAPI = (file: File) => {
  const formData = new FormData();
  // 直接传入File实例作为字段值,键名和后端保持一致为'file'
  formData.append('file', file);
  // 不传第三个contentType参数
  request(`urlUploadFile`, {
    method: 'POST',
    body: formData
  }).subscribe({
    next: (res) => {
      // 处理上传成功逻辑
      console.log('上传成功', res);
    },
    error: (err) => {
      // 处理上传失败逻辑
      console.error('上传失败', err);
    }
  });
}
验证方式

打开浏览器开发者工具的网络面板,找到上传请求:

  • 查看请求头,Content-Type值应为multipart/form-data; boundary=----WebKitFormBoundaryxxx格式,携带自动生成的随机边界字符串
  • 查看请求载荷,可看到被边界字符串分隔的file字段,内容为上传的文件二进制数据
    满足以上两点时,Flask后端即可正常通过request.files['file']获取到上传的文件对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:03:29