Dio 进阶用法:Flutter 网络请求中 FormData 与文件上传解析

一、FormData 核心概念
  1. 本质
    HTTP 请求中用于封装multipart/form-data格式数据的容器,支持混合传输文本和二进制数据。

  2. 核心方法

    FormData formData = FormData.fromMap({
      "text_field": "value",  // 文本字段
      "file_field": await MultipartFile.fromFile(path) // 文件字段
    });
    


二、文件上传实现流程
1. 单文件上传
// 创建FormData
FormData data = FormData.fromMap({
  "username": "user123",
  "avatar": await MultipartFile.fromFile(
    "/path/to/image.jpg",
    filename: "profile.jpg" // 建议指定文件名
  ),
});

// 发送请求
Response response = await Dio().post(
  "/upload",
  data: data,
  options: Options(contentType: "multipart/form-data")
);

2. 多文件批量上传
List<MultipartFile> files = [
  await MultipartFile.fromFile("/path/file1.pdf"),
  await MultipartFile.fromFile("/path/file2.png"),
];

FormData data = FormData.fromMap({
  "doc_type": "contract",
  "attachments": files  // 文件列表
});


三、关键配置项
参数 作用 示例值
filename 服务器接收的文件名 "invoice_2023.pdf"
contentType 文件MIME类型(自动推断可省略) MediaType("image","jpeg")
onSendProgress 上传进度回调 (sent, total) => print(sent/total)

四、常见问题解决方案
  1. 文件过大导致超时

    Dio dio = Dio(BaseOptions(
      sendTimeout: 60 * 1000, // 60秒超时
      receiveTimeout: 60 * 1000
    ));
    

  2. Android 文件路径问题

    // 使用path_provider获取合法路径
    String appDir = (await getApplicationDocumentsDirectory()).path;
    String filePath = "$appDir/files/target.jpg";
    

  3. 服务器接收异常

    • 检查请求头是否包含:Content-Type: multipart/form-data
    • 验证字段名是否与服务器接口一致

五、完整示例
void uploadImage() async {
  // 1. 选择文件
  File imageFile = File(await _pickImage()); 

  // 2. 构建FormData
  FormData formData = FormData.fromMap({
    "userId": "U1001",
    "comment": "项目设计图",
    "image": await MultipartFile.fromFile(
      imageFile.path,
      filename: "design_${DateTime.now().millisecondsSinceEpoch}.png"
    )
  });

  // 3. 发送请求
  try {
    Response res = await Dio().post(
      "https://api.example.com/upload",
      data: formData,
      onSendProgress: (int sent, int total) {
        print("进度: ${(sent/total*100).toStringAsFixed(1)}%");
      },
    );
    print("上传成功: ${res.data}");
  } catch (e) {
    print("上传失败: $e");
  }
}

最佳实践

  • 大文件上传建议分片处理
  • 生产环境添加请求拦截器处理鉴权
  • 使用CancelToken实现上传取消功能
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐