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

如何在Dart中追踪Multipart数据任务的上传进度?

监听Dart http.MultipartRequest的上传进度

你提到的response.stream.listen确实只能监听响应(下载)的进度,要获取上传进度,需要对请求体的字节流进行包装,在数据发送过程中统计已上传的字节数。

实现步骤

  1. 计算整个请求的总字节数(包含multipart分隔符、文件数据等所有要上传的内容);
  2. 包装请求体的原始Stream,在每个数据块发送时累加已上传字节并计算进度;
  3. 使用包装后的Stream发送请求。

完整代码示例

import 'dart:io';
import 'package:http/http.dart' as http;

void main() async {
  // 准备上传的文件
  final file = File('path/to/your/file');
  final uploadUrl = Uri.parse('https://your-upload-endpoint.com');

  // 创建MultipartRequest
  var request = http.MultipartRequest('POST', uploadUrl);
  request.files.add(await http.MultipartFile.fromPath('file', file.path));
  
  // 获取整个请求的总字节数
  final totalUploadBytes = await request.contentLength;
  int uploadedBytes = 0;

  // 包装原始请求体Stream,添加进度监听
  final progressStream = request.finalize().transform(StreamTransformer.fromHandlers(
    handleData: (dataChunk, sink) {
      uploadedBytes += dataChunk.length;
      // 计算进度(0-1之间的浮点数,可转为百分比)
      final uploadProgress = uploadedBytes / totalUploadBytes;
      print('上传进度:${(uploadProgress * 100).toStringAsFixed(2)}%');
      // 这里可以将进度传递给UI更新,比如通过StatefulWidget的setState

      // 继续传递数据块,不影响上传流程
      sink.add(dataChunk);
    },
    handleError: (error, stackTrace, sink) {
      sink.addError(error, stackTrace);
    },
    handleDone: (sink) {
      sink.close();
    },
  ));

  // 使用包装后的Stream发送请求
  final client = http.Client();
  final response = await client.send(
    http.StreamedRequest(request.method, request.url)
      ..headers.addAll(request.headers)
      ..contentLength = totalUploadBytes
      ..sink.addStream(progressStream)
      ..sink.close(),
  );

  // 处理响应
  final responseBody = await http.Response.fromStream(response);
  print('上传完成,响应状态码:${response.statusCode}');
  print('响应内容:${responseBody.body}');
}

复用工具函数

如果需要在多个地方使用,可以把进度监听逻辑封装成工具函数:

Stream<List<int>> withUploadProgress(
  Stream<List<int>> originalStream,
  int totalBytes,
  void Function(double progress) onProgress,
) {
  int uploaded = 0;
  return originalStream.transform(StreamTransformer.fromHandlers(
    handleData: (data, sink) {
      uploaded += data.length;
      final progress = uploaded / totalBytes;
      onProgress(progress);
      sink.add(data);
    },
  ));
}

使用时只需替换包装Stream的部分:

final progressStream = withUploadProgress(
  request.finalize(),
  totalUploadBytes,
  (progress) {
    print('上传进度:${(progress * 100).toStringAsFixed(2)}%');
  },
);

关键说明

  • request.finalize()会生成包含所有上传内容的原始字节流,包括multipart协议的分隔符、文件数据、表单字段等;
  • 通过StreamTransformer包装流,既能正常传递上传数据,又能在每个数据块发送时统计进度;
  • 必须使用StreamedRequest来发送包装后的流,才能保留进度监听逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:37:24