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

Token过期后重发Multipart请求时遭遇异常问题

解决Multipart请求重试时的"Can't finalize a finalized MultipartFile"错误

问题根源

MultipartFile基于流式传输实现,首次发送请求时文件流已被完全消耗并关闭(finalized),重试时无法重复读取同一个流对象,因此触发该错误。

可行解决方案

方案1:每次重试时重新构建MultipartRequest

不要复用原有的MultipartRequest实例,将请求构建逻辑封装为可重复调用的方法,确保每次重试都生成全新的请求对象和文件流。

代码修改示例:

首先封装请求构建方法:

Future<http.MultipartRequest> buildMultipartRequest(
  String url, 
  Map<String, String> headers, 
  Map<String, String> fields, 
  List<String>? filePaths, 
  List<String>? fileKeys
) async {
  var request = http.MultipartRequest('POST', Uri.parse(url));
  request.headers.addAll(headers);
  request.fields.addAll(fields);

  if (filePaths != null && fileKeys != null) {
    for (int i = 0; i < filePaths.length; i++) {
      // 每次调用fromPath都会重新打开文件流,避免复用已关闭的流
      request.files.add(await http.MultipartFile.fromPath(fileKeys[i], filePaths[i]));
    }
  }
  return request;
}

然后在重试逻辑中覆盖retryRequest方法,重新生成请求:

class ExpiredTokenRetryPolicy extends RetryPolicy {
  @override
  int get maxRetryAttempts => 1;

  // 保存构建请求所需的参数(需在初始化时传入)
  final String url;
  final Map<String, String> headers;
  final Map<String, String> fields;
  final List<String>? filePaths;
  final List<String>? fileKeys;

  ExpiredTokenRetryPolicy({
    required this.url,
    required this.headers,
    required this.fields,
    this.filePaths,
    this.fileKeys,
  });

  @override
  Future<bool> shouldAttemptRetryOnResponse(http.BaseResponse response) async {
    if (response.statusCode == 401) {
      return await refreshToken();
    }
    return false;
  }

  @override
  Future<BaseRequest> retryRequest(BaseRequest request, BaseResponse response) async {
    // 重试时重新构建Multipart请求
    return await buildMultipartRequest(url, headers, fields, filePaths, fileKeys);
  }
}

方案2:将文件内容读入内存生成可复用的MultipartFile

把文件内容一次性读取到内存中,生成基于字节数组的MultipartFile,这样每次重试都可以重新生成流(适合小文件场景)。

代码示例:

Future<http.MultipartFile> createReusableMultipartFile(String key, String path) async {
  final fileBytes = await File(path).readAsBytes();
  return http.MultipartFile.fromBytes(
    key,
    fileBytes,
    filename: path.split('/').last,
  );
}

在构建请求时使用该方法替代fromPath,即可实现流的重复读取。

关键注意事项

  • 使用fromPath时,每次调用都会重新打开文件流,不会占用过多内存,适合大文件场景。
  • 基于字节数组的方式虽然能复用流,但大文件会导致内存占用过高,需谨慎使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 17:21:13