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

Flutter如何使用HttpClient向服务器发送数据并获取上传进度百分比

问题解答

结论

使用HttpClient完全可以获取上传进度,你当前的实现存在多处逻辑错误,修正后即可正常获取进度。

现有代码的错误点

  • 重复提交请求体:同时调用了request.addStream(streamUpload)和request.add(utf8.encode(body)),实际生效的是后者,前者的进度监听逻辑完全没有参与数据上传
  • 自定义流没有输出数据:你在StreamTransformer的handleData回调里只统计了字节长度,没有调用sink.add把数据传递到请求流里,addStream相当于上传了空内容
  • 总长度计算错误:body.length是字符串的字符数,UTF8编码后多字节字符的字节数会大于字符数,和实际上传的字节长度不匹配,会导致进度计算不准,甚至请求头Content-Length和实际长度不一致被服务端拒绝
  • 缺少进度输出逻辑:仅统计了已上传字节数,没有对应的进度计算、输出逻辑,无法直观看到进度变化

修正后的实现代码

import 'dart:convert';
import 'dart:io';

void postDataWithProgress() async {
  HttpClient httpClient = HttpClient();
  var url = "https://xxxxxxx/api/adddata";
  HttpClientRequest request =
      await httpClient.postUrl(Uri.parse(url)).timeout(const Duration(seconds: 10));

  var datavalue = {
    "listvideoname": ["a", "b", "c"],
    "listvideobase64": ["adahd", "ayuiary", "oukjfjka"]
  };
  var body = json.encode(datavalue);
  // 编码为UTF8字节数组,计算正确的总字节长度
  List<int> bodyBytes = utf8.encode(body);
  int totalByteLength = bodyBytes.length;
  int uploadedByteCount = 0;

  // 直接从字节数组构建上传流
  Stream<List<int>> streamUpload = Stream.fromIterable([bodyBytes])
      .transform(StreamTransformer.fromHandlers(
    handleData: (data, sink) {
      // 传递数据到请求流
      sink.add(data);
      // 累加已上传字节
      uploadedByteCount += data.length;
      // 计算并打印进度,保留两位小数
      double progress = uploadedByteCount / totalByteLength * 100;
      print("当前上传进度:${progress.toStringAsFixed(2)}%");
    },
    handleDone: (sink) {
      sink.close();
    },
    handleError: (error, stackTrace, sink) {
      sink.addError(error, stackTrace);
    },
  ));

  // 设置请求头
  request.contentLength = totalByteLength;
  request.headers.set(
    "Content-Type", 
    "application/json", 
    preserveHeaderCase: true
  );
  request.headers.set(
    "Authorization", 
    "Bearer $token", 
    preserveHeaderCase: true
  );

  // 仅调用addStream上传,不要额外调用add方法
  await request.addStream(streamUpload);
  HttpClientResponse response = await request.close();
  if (response.statusCode == 200) {
    print("add data success");
  } else {
    print("add data error,状态码:${response.statusCode}");
  }
  httpClient.close();
}

额外优化建议

如果上传的内容体积很大,不建议把整个内容转成base64放到JSON里,会额外增加33%的体积,直接用multipart/form-data格式上传原文件,进度统计会更准确,内存占用也更低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:06:03