如何创建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
相关产品推荐
相关产品推荐

