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

Flutter Web上传图片返回200状态码但文件损坏 多实现方案均失效

问题根因

你使用的是对象存储的预签名URL(Signed URL)进行上传,这类上传接口要求直接PUT文件的原始二进制数据流,而你当前两种实现都将文件封装进了FormData/MultipartRequest结构中,服务端会将FormData的边界标识、字段头等额外信息一同写入文件,最终导致图片格式损坏。

修正后的代码实现

1. 基于dio的上传修正

uploadImageWeb(Uint8List fileBytes, String? fileName) async {
  var dioo = Dio();
  try {
    String? sUrl = await _profileController.getSignedUrl("profile");
    if (sUrl == null) {
      print("Signed Url is null");
      return;
    }
    _profileController.isPicUploading(true);
    // 从文件名获取正确的MIME类型
    String? mimeType = lookupMimeType(fileName ?? '');
    var response = await dioo.put(
      sUrl,
      data: Stream.fromIterable(fileBytes.map((e) => [e])), // 直接传二进制流
      options: Options(
        headers: {
          Headers.contentTypeHeader: mimeType ?? 'image/jpeg', // 正确设置Content-Type请求头
          Headers.contentLengthHeader: fileBytes.length, // 必须设置内容长度
          "Authorization": "Bearer",
        },
      ),
    );
    if (response.statusCode == 200) {
      print("上传成功,状态码:${response.statusCode}");
    } else {
      print("上传失败,状态码:${response.statusCode}");
    }
  } catch (e) {
    print("上传异常:$e");
  } finally {
    _profileController.isPicUploading(false);
  }
}

2. 基于http的上传修正

imageUploadWithHttp(Uint8List? fileBytes, String? fileName) async {
  if (fileBytes == null || fileName == null) return;
  try {
    String? sUrl = await _profileController.getSignedUrl("profile");
    if (sUrl == null) {
      print("Signed Url is null");
      return;
    }
    _profileController.isPicUploading(true);
    String? mimeType = lookupMimeType(fileName);
    // 直接使用普通PUT请求,不要用MultipartRequest
    var response = await http.put(
      Uri.parse(sUrl),
      body: fileBytes, // 直接传二进制字节数组
      headers: {
        Headers.contentTypeHeader: mimeType ?? 'image/jpeg',
        Headers.contentLengthHeader: fileBytes.length.toString(),
        "file-name": fileName,
      },
    );
    if (response.statusCode == 200) {
      print("上传成功");
    } else {
      print("上传失败,状态码:${response.statusCode}");
    }
  } catch (e) {
    print("上传异常:$e");
  } finally {
    _profileController.isPicUploading(false);
  }
}

额外验证步骤

  • 上传前可以先计算本地文件字节的MD5值,上传完成后从服务端下载文件重新计算MD5,两者一致则说明传输正确
  • 确认预签名URL生成时指定的Content-Type和上传时传入的Content-Type一致,部分云存储会校验该参数匹配性
  • 不要在请求头中加Access-Control-Allow-Origin,该字段是服务端返回的响应头,请求侧携带无意义反而可能导致跨域错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 16:45:04