【问题标题】:Uploaded file to S3 via PreSigned URL from Flutter App. but the file is corrupted when i download it通过 Flutter App 的 PreSigned URL 将文件上传到 S3。但是当我下载它时文件已损坏
【发布时间】:2019-10-27 21:18:47
【问题描述】:

我正在开发一个 Flutter 应用程序,我在其中使用预签名 URL 将图像文件(PUT 请求)上传到 AWS S3。上传成功,因为我可以在 S3 中看到该文件。但是当我点击并从存储桶中下载它时,下载的文件已损坏。

我正在使用 Dio 库来上传文件。 通过邮递员将图像文件上传为二进制文件效果很好

uploadFileToPresignedS3(
    File payload, String fileName, String presignedURL) async {
  try {
    Dio dio = new Dio();

    FormData formData = new FormData.from(
        {"name": fileName, "file1": new UploadFileInfo(payload, fileName)});
    dio.put(presignedURL, data: formData);
  } catch (ex) {
    print(ex);
  }
}


预期:上传的文件不会损坏

实际结果:上传的文件已损坏

【问题讨论】:

  • 更新:我尝试使用 javascript XHR 上传,效果很好。
  • 我没有使用 Dio 库,而是使用了 http.put(presignedURL, body: payload.readAsBytesSync());效果很好。
  • 我也遇到了这个问题,可以分享一下代码吗?
  • http.put() 工作正常...但是如何使用 put() 获取上传进度? Dio 提供了一个“onSendProgress”方法来执行此操作。

标签: amazon-web-services amazon-s3 flutter pre-signed-url


【解决方案1】:

使用此代码使用 Dio 将文件(图像)上传到 S3 预签名 URL 并显示 上传进度:

await dio.put(
    url,
    data: image.openRead(),
    options: Options(
      contentType: "image/jpeg",
      headers: {
        "Content-Length": image.lengthSync(),
      },
    ),
    onSendProgress: (int sentBytes, int totalBytes) {
      double progressPercent = sentBytes / totalBytes * 100;
      print("$progressPercent %");
    },
  );

注意:不要像这样将 Content-Type 标头与 Content-Length 一起设置:

headers: {
   "Content-Length": image.lengthSync(),
   "Content-Type": "image/jpeg",
},

由于某些原因,会导致上传文件损坏。

以防万一:您可以使用 setState() 代替 print("$progressPercent %") 在 UI 中显示更新。

希望这会有所帮助。

【讨论】:

  • 我尝试了上述解决方案,但没有奏效。但是经过一些跟踪和错误后,我发现令人惊讶地发送“授权”标头是我的错误。如果您要发送它,请尝试将其删除。
  • 它可以工作,但是当我上传图片时需要图片网址作为响应。
  • 在浪费了 3 天之后,我终于想出了您的解决方案。这是在遇到情况下唯一有效的答案。谢谢
【解决方案2】:

要背负 Rabi Roshans 的评论,您需要将 contenType 修改为“application/octet-stream”。在后端的 S3 参数中,您需要执行相同的操作。

客户端代码

  await dio.put(
    url,
    data: image.openRead(),
    options: Options(
      contentType: "application/octet-stream",
      headers: {
        "Content-Length": image.lengthSync(),
      },
    ),
    onSendProgress: (int sentBytes, int totalBytes) {
      double progressPercent = sentBytes / totalBytes * 100;
      print("$progressPercent %");
    },
  );

s3 后端

  var presignedUrl = s3.getSignedUrl("putObject", {
    Bucket: "your_bucke_name",
    Key: "filename.ext", 
    Expires: 120, // expirations in seconds
    ContentType: "application/octet-stream", // this must be added or you will get 403 error
  })

;

【讨论】:

    【解决方案3】:

    我创建了这个类来使用预签名的 url 将图像发送到 s3,我正在使用相机库将照片发送到 s3。

    import 'dart:convert';
    import 'dart:io';
    
    import 'package:camera/camera.dart';
    import 'package:http/http.dart';
    import 'package:http_parser/http_parser.dart';
    
    class AwsApi {
      Future<String> uploadToSignedUrl({required XFile file, required String signedUrl}) async {
        Uri uri = Uri.parse(signedUrl);
        var response = await put(uri, body: await file.readAsBytes(), headers: {"Content-Type": "image/jpg"});
    
        return response;
    
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-25
      • 2020-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-09
      相关资源
      最近更新 更多