Flutter 中的 Dio FormData:将多部分文件发送到 API 时出错,导致错误类型“String”不是类型转换中“Map<String, dynamic>”类型的子类型

问题描述 投票:0回答:1
type 'String' is not a subtype of type 'Map<String, dynamic>' in type cast

我正在开发一个 Flutter 应用程序,用户可以在其中更新他们的个人资料,包括上传个人资料图片和封面照片。我正在使用 Dio 处理 HTTP 请求和分段文件上传。

我无法将图像文件(例如,个人资料图片和封面照片)上传到后端。请求不断失败,并出现与 FormData 格式化方式相关的错误。我怀疑 Dio 没有正确解释 FormData。

下面是我的代码的简化版本。

Future<void> updateUserProfile({
  File? coverPhoto,
  File? profilePhoto,
}) async {
  try {
    // Prepare the form data with fields
    FormData formData = FormData.fromMap({
      "first_name": "Tupac",
      "last_name": "shakur",
      "email": "[email protected]",
    });

    // Add cover photo if it exists
    if (coverPhoto != null) {
      final result = _preparePhotoFile(coverPhoto, "cover photo");
      if (result is String) {
        print(result);
        return; // Stop if there's an error
      }

      final [type, subtype] = result as List<String>;
      formData.files.add(
        MapEntry(
          "cover_photo",
          await MultipartFile.fromFile(
            coverPhoto.path,
            filename: path.basename(coverPhoto.path),
            contentType: MediaType(type, subtype),
          ),
        ),
      );
    }

    // Add profile photo if it exists
    if (profilePhoto != null) {
      final result = _preparePhotoFile(profilePhoto, "profile picture");
      if (result is String) {
        print(result);
        return; // Stop if there's an error
      }

      final [type, subtype] = result as List<String>;
      formData.files.add(
        MapEntry(
          "profile_picture",
          await MultipartFile.fromFile(
            profilePhoto.path,
            filename: path.basename(profilePhoto.path),
            contentType: MediaType(type, subtype),
          ),
        ),
      );
    }

    // Sending the request
    Dio dio = Dio();
    final response = await dio.post(
      "https://example.com/update-profile",
      data: formData,
      options: Options(contentType: "multipart/form-data"),
    );

    print(response.data);
  } catch (e) {
    print('Error: $e');
  }
}
/// Prepares the photo file by validating its MIME type and ensuring it's in an accepted format.
dynamic _preparePhotoFile(File photo, String fieldName) {
  // Determine MIME type of the file
  final mimeType = lookupMimeType(photo.path);

  // Validate MIME type is supported
  if (mimeType == null) {
    return 'Unsupported image format for $fieldName';
  }

  // Check if MIME type is among the supported image formats
  if (!['image/jpeg', 'image/png', 'image/bmp', 'image/webp'].contains(mimeType)) {
    return 'Unsupported image format for $fieldName';
  }

  // Return MIME type split into type and subtype (e.g., "image/jpeg" -> "image", "jpeg")
  return mimeType.split('/');
}

我已采取的故障排除步骤:

  1. 检查文件路径和验证 确保文件存在并且可以访问。记录文件路径并确认其正确。
  2. 使用和不使用文件进行测试
  3. 检查了后端日志,但由于错误,请求从未发送
flutter flutter-dependencies dio
1个回答
0
投票

似乎

FormData.fromMap()
可能无法正确编码文件数据。您可以尝试将其替换为包含 JSON 数据和文件对象的简单
Map<String, dynamic>
,然后使用
FormData
对其进行编码。这是示例代码:

Future<void> updateUserProfile({
  File? coverPhoto,
  File? profilePhoto,
}) async {
  try {
    Map<String, dynamic> formDataMap = {
      "first_name": "Tupac",
      "last_name": "shakur",
      "email": "[email protected]",
    };
    // Prepare the form data with fields
    // FormData formData = FormData.fromMap({
    //   "first_name": "Tupac",
    //   "last_name": "shakur",
    //   "email": "[email protected]",
    // });

    // Add cover photo if it exists
    if (coverPhoto != null) {
      final result = _preparePhotoFile(coverPhoto, "cover photo");
      if (result is String) {
        print(result);
        return; // Stop if there's an error
      }

      final [type, subtype] = result as List<String>;
      formDataMap.addAll({"cover_photo": await MultipartFile.fromFile(
        coverPhoto.path,
        filename: path.basename(coverPhoto.path),
        contentType: MediaType(type, subtype),
      )});
      // formData.files.add(
      //   MapEntry(
      //     "cover_photo",
      //     await MultipartFile.fromFile(
      //       coverPhoto.path,
      //       filename: path.basename(coverPhoto.path),
      //       contentType: MediaType(type, subtype),
      //     ),
      //   ),
      // );
    }

    // Add profile photo if it exists
    if (profilePhoto != null) {
      final result = _preparePhotoFile(profilePhoto, "profile picture");
      if (result is String) {
        print(result);
        return; // Stop if there's an error
      }

      final [type, subtype] = result as List<String>;
      formDataMap.addAll({"profile_picture": await MultipartFile.fromFile(
        profilePhoto.path,
        filename: path.basename(profilePhoto.path),
        contentType: MediaType(type, subtype),
      )});
      // formData.files.add(
      //   MapEntry(
      //     "profile_picture",
      //     await MultipartFile.fromFile(
      //       profilePhoto.path,
      //       filename: path.basename(profilePhoto.path),
      //       contentType: MediaType(type, subtype),
      //     ),
      //   ),
      // );
    }

    // Sending the request
    Dio dio = Dio();
    final response = await dio.post(
      "https://example.com/update-profile",
      data: FormData.fromMap(formDataMap),
      options: Options(contentType: "multipart/form-data"),
    );

    print(response.data);
  } catch (e) {
    print('Error: $e');
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.