React Native - S3 Pre-signed URL 上传问题。 cURL 有效,fetch 无效 - 403 SignatureDoesNotMatch

React Native - S3 Pre-signed URL upload issues. cURL works, fetch doesn't - 403 SignatureDoesNotMatch

如标题所示,我可以毫无问题地从 lambda 获得 pre-signed URL。 URL 在 cURL 中工作,可以毫无问题地上传图像,并且还可以与测试 python 脚本一起工作。

我一辈子都弄不明白为什么这在 javascript 中不起作用(特别是 React Native,在 Expo 中)。

这里大致是感兴趣的代码:

const getBlob = async (fileUri) => {
    const resp = await fetch(fileUri);
    const imageBody = await resp.blob();
    
    return imageBody;
  };


async function putPhoto(photoURI){
// code to get the S3URL

    const imageBlob = await getBlob(photoURI)

    response = await fetch(S3URL,{
            method: "PUT",    
            body: imageBlob,
            // headers: {
            //     "Content-Type": "application/json"
            // }
         
        })

特别令人抓狂,因为来自 S3 的响应包含 URL,我可以显式地 cURL 并成功解析:

curl -X PUT -T .\test.jpg "https://<bucketname>.s3.amazonaws.com/<lambda generated hash>.jpg?AWSAccessKeyId=<>&x-amz-security-token=<>&Expires=<>"

当然 'sensitive data' 在 <> 中被替换。

我唯一能看到其他人有共同问题的是 headers - 我也尝试输入:

headers: {}

我假设这会覆盖 headers 的任何全局范围,我忘记了。

有什么建议吗?非常感谢。

好的,看起来 S3 在获取 fetch() 请求时非常具体地需要正确的 header,而不关心来自 cURL 的那些相同的 header。或者至少,在这种情况下需要这样设置才能获取。

Python lambda 代码:

url = boto3.client('s3').generate_presigned_url(
        ClientMethod='put_object', 
        Params={'Bucket': BUCKET_NAME, 'Key': full_id, 'ContentType': 'application/octet-stream'},
        ExpiresIn=3600
    )

关键是添加 Content-Type 参数,如图所示。

此外,将我上面的代码更改为(参见 Content-Type):

async function putPhoto(photoURI){
// code to get the S3URL

    const imageBlob = await getBlob(photoURI)

    response = await fetch(S3URL,{
            method: "PUT",    
            body: imageBlob,
            headers: {
                "Content-Type": "application/octet-stream"
            }
         
        })