使用预签名URL上传到AWS S3的MP4视频无法播放

6
我正在使用预签名URL将一个 mp4 视频上传到 AWS S3,上传成功后,当我尝试从S3下载视频并在媒体播放器(VLC或QuickTime)中播放时,它无法播放!
生成的预签名URL与 mp3 一起使用时运行良好,但对于 WAVFLAC,也会出现上述相同的问题。
生成预签名URL的代码:
public String getPreSignedS3Url( final String userId, final String fileName )
    {
        Date expiration = new Date();
        long expTimeMillis = expiration.getTime();
        expTimeMillis += urlExpiry;
        expiration.setTime(expTimeMillis);

        String objectKey = StringUtils.getObjectKey( userId, fileName );

        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(
                recordingBucketName, objectKey)
                .withMethod(HttpMethod.PUT)
                .withExpiration(expiration);

        URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);

        return url.toString();

    }

之前提到的获取预签名 URL 的方法,得到后我们可以通过 Postman 发送一个包含 multipart/form-data 数据的 HTTP PUT 请求,请求体应该长这样:

-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
  -F 'file=@/Users/john/Downloads/sampleDemo.mp4'

预签名的 URL 类似于这样:

https://meeting-recording.s3.eu-west-2.amazonaws.com/331902257/sampleDemo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20190720T125751Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3599&X-Amz-Credential=AKIAZDSMLZ3VDKNXQUXH%2F20190720%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Signature=dfb8054f0738e07e925e9880e4a8e5ebba0a1bd3c84a3ec78913239f65221992

我尝试在getPreSignedS3Url()方法中使用generatePresignedUrlRequest.setContentType( "video/mp4" );设置内容类型为mp4,并在HTTP PUT请求标头中添加Content-Type : "video/mp4",但它没有起作用并且因错误签名不符而失败。

我正在使用S3作为我的个人备份硬盘,我希望使用预签名URL将视频和音频文件上传到S3,将来可以下载它们并能够播放,但我无法在下载后播放它们。

有谁知道是什么原因导致这种情况?

3个回答

3

PUT 请求不支持 multipart/form-data 格式。请求体中只能包含二进制对象数据,不能包含其他内容。如果您从 S3 下载现有文件并在文本编辑器中打开它,您会发现 S3 保留了文件内部的多部分表单结构,而不是将其解释为实际负载的封装。


谢谢,我会尝试一下,但为什么 multipart/form-data 对于 mp3 起作用呢? - Junes
1
我想不出为什么会奏效的解释,除非mp3播放器在解释文件时非常慷慨。使用md5sum或sha256sum这样的工具来计算上传文件之前和下载文件之后的校验和,你会发现以这种方式上传实际上正在破坏文件。一个更简单的测试是,你还应该发现下载的文件实际上比原始文件要大。如果尺寸和校验和匹配,则实际上没有发送multipart/form-data,但这似乎不太可能。 - Michael - sqlbot
你是我的英雄。现在一切都有意义了。谢谢你。 - c..
那么,解决方案是什么? - Pavlo Sharhan

0
为了补充上面的答案(对于未来的读者),我使用formData()像下面这样发送put请求。直接将文件添加到负载中对我有用。
不要这样做:
var bodyData = new FormData();
bodyData.append('file', video);

axios.put(res?.data?.uploadURL, bodyData, {

相反,这样做:

axios.put(res?.data?.uploadURL, video, {

0

1.generatePresignedUrlRequest.setContentType("video/mp4");

2. 对于您的HTTP请求, 请添加头部信息,Content-Type: video/mp4 并将内容设置为二进制格式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接