【问题标题】:How do I upload a file to a pre-signed URL in AWS using Node.js and Axios?如何使用 Node.js 和 Axios 将文件上传到 AWS 中的预签名 URL?
【发布时间】:2020-04-19 13:53:13
【问题描述】:

我有下一个场景:

  1. 为 AWS-SDK 上传文件生成签名 URL
  2. 尝试使用axios(或请求)npm包上传本地文件

但每次我有错误:

状态:403 statusText:禁止

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>FakeKeyId</AWSAccessKeyId><StringToSign>PUT

application/json;charset=utf-8
1577742550
/test-bucket-super/xxx/test.mp3</StringToSign><SignatureProvided>DAAOZ0/VkMNEMMlGkRUsSuRO3J4=</SignatureProvided><StringToSignBytes>50 55 54 0a 0a 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 3b 63 68 61 72 73 65 74 3d 75 74 66 2d 38 0a 31 35 37 37 37 34 32 35 35 30 0a 2f 74 65 73 74 2d 62 75 63 6b 65 74 2d 73 75 70 65 72 2f 78 78 78 2f 74 65 73 74 2e 6d 70 33</StringToSignBytes><RequestId>CBD3F1D0D02EA874</RequestId><HostId>LPu+RQ8otcljI1Wt5FiZm+UmTFNiCX+2HyGtN0kTAugLiT21M55DtbzQdF/s7qOCSaZvzTp4kw4=</HostId></Error>
const axios = require('axios');
const AWS = require('aws-sdk')

const s3 = new AWS.S3({
    accessKeyId: 'FakeKeyId',
    secretAccessKey: 'xxxxxxxxxxxxxxxxxxxxxxxx',
    region: 'eu-west-1'
});

const fs = require('fs');
const readFile = require('util').promisify(fs.readFile);

(async () => {
    try {
        const presignedS3Url = s3.getSignedUrl('putObject', {
            Bucket: 'test-bucket-super',
            Key: 'xxx/test.mp3'
        });
        const file = await readFile('./SampleAudio_0.4mb.mp3');

        const axiosResponse = await axios.put(presignedS3Url, {
            data: file,
        });
        console.info(axiosResponse)
    } catch (e) {
        console.error(e)
    }
})();

但我设法通过 cURL 上传文件

curl -X PUT -T ~/Downloads/SampleAudio_0.4mb.mp3 'https://test-bucket-super.s3.eu-west-1.amazonaws.com/xxx/test.mp3?AWSAccessKeyId=FakeKeyId&Expires=1577741900&Signature=9kPiC%2B85SEFp6g5C3nwEWe4TueU%3D' -v

【问题讨论】:

  • 你还需要帮助吗

标签: node.js amazon-web-services http amazon-s3 axios


【解决方案1】:

这里的问题是,axios 出于某种原因添加了默认的Content-Type: application/json 标头。这就是签名不匹配的原因。我不确定如何删除标题。

但以下对我有用,我在签名生成期间包含content-type。我在使用时也包含相同的标题。

(async () => {
  try {
    const presignedS3Url = s3.getSignedUrl('putObject', {
      Bucket: 'bucket-name',
      Key: 'car.jpg',
      ContentType: 'application/octet-stream'
    });
    const file = await readFile('./car.jpg');

    const axiosResponse = await axios.put(presignedS3Url, {
      data: file,

    }, {
      headers: {
        'Content-Type': 'application/octet-stream'
      }
    });
    console.info(axiosResponse)
  } catch (e) {
    console.error(e)
  }
})();

【讨论】:

  • 很高兴为您提供帮助
  • 这是从请求中删除内容类型的方法:{headers: { 'Content-Type' : '' }}
  • axios.put 中的第二个参数不应该只是file 而不是{ data: file }?否则,它会上传一个带有缓冲区内容的 JSON 对象。
【解决方案2】:

您的请求需要与签名完全匹配。一个明显的问题是您实际上并未在请求中包含预设 ACL,即使您将其包含在签名中也是如此。改为:

var options = { headers: { 'Content-Type': fileType, 'x-amz-acl': 'public-read' } };

【讨论】:

  • 我在原始问题中没有看到任何预设 ACL。
猜你喜欢
  • 2019-01-11
  • 1970-01-01
  • 1970-01-01
  • 2020-10-23
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 2021-12-18
  • 2020-09-30
相关资源
最近更新 更多