【问题标题】:How to write to an existing file in a S3 bucket based on the pre signed URL?如何根据预签名 URL 写入 S3 存储桶中的现有文件?
【发布时间】:2019-11-12 08:20:06
【问题描述】:

我一直在寻找一种从预签名 URL 写入 S3 存储桶中的 JSON 文件的方法。根据我的研究,它似乎可以完成,但这些不在 Node 中:

没有从我的搜索中找到节点解决方案并使用第 3 方 API 我正在尝试将回调写入 S3 存储桶中的 JSON。我可以毫无问题地生成预签名 URL,但是当我尝试将虚拟文本写入预签名 URL 时,我得到:

错误:ENOENT:没有这样的文件或目录,打开 'https://path-to-file-with-signed-url'

当我尝试使用writeFile:

fs.writeFile(testURL, `This is a write test: ${Date.now()}`, function(err) {
  if(err) return err
  console.log("File written to")
})

我对@9​​87654331@ 下的documentation 的理解表明我可以使用URL。我开始相信这可能是权限问题,但我在文档中找不到任何运气。

在实现node-fetch 后,我仍然收到错误 (403 Forbidden) 根据预签名 URL 写入 S3 中的文件,这是我编写的模块的完整代码:

const aws = require('aws-sdk')
const config = require('../config.json')
const fetch = require('node-fetch')
const expireStamp = 604800 // 7 days

const existsModule = require('./existsModule')

module.exports = async function(toSignFile) {
  let checkJSON = await existsModule(`${toSignFile}.json`)
  if (checkJSON == true) {
    let testURL = await s3signing(`${toSignFile}.json`)
    fetch(testURL, {
      method: 'PUT',
      body: JSON.stringify(`This is a write test: ${Date.now()}`),
    }).then((res) => {
      console.log(res)
    }).catch((err) => {
      console.log(`Fetch issue: ${err}`)
    })
  }
}

async function s3signing(signFile) {
  const s3 = new aws.S3()
  aws.config.update({
    accessKeyId: config.aws.accessKey,
    secretAccessKey: config.aws.secretKey,
    region: config.aws.region,
  })
  params = {
    Bucket: config.aws.bucket,
    Key: signFile,
    Expires: expireStamp
  }
  try {
    // let signedURL = await s3.getSignedUrl('getObject', params)
    let signedURL = await s3.getSignedUrl('putObject', params)
    console.log('\x1b[36m%s\x1b[0m', `Signed URL: ${signedURL}`)
    return signedURL
  } catch (err) {
    return err
  }
}

查看权限我在权限中设置了上传和写入权限没有问题。在 Node 中,如何使用该文件的预签名 URL 作为路径写入 S3 存储桶中的文件?

【问题讨论】:

  • 您确定您用于签署请求的 AWS 凭证实际上允许 s3:PutObject 到该 S3 存储桶吗?也许用 awscli 验证这一点。另请参阅aws.amazon.com/premiumsupport/knowledge-center/… 了解有关诊断 403 的一些建议(使用控制台,但内容仍然有价值)。

标签: node.js amazon-web-services url amazon-s3 aws-lambda


【解决方案1】:

fs文件系统 模块。您不能将其用作 HTTP 客户端。

您可以使用内置的https 模块,但我认为您会发现使用node-fetch 更容易。

fetch('your signed URL here', {
  method: 'PUT',
  body: JSON.stringify(data),
  // more options and request headers and such here
}).then((res) => {
  // do something
}).catch((e) => {
  // do something else
});

【讨论】:

  • 谢谢,这有点接近,但我收到了403 Forbidden。我在某处遗漏了一些东西,需要进行更多研究。
  • 确保您的网址已签名以允许PUT
  • 是的,我正在使用putObject,我的回复是403 Forbidden,我刚刚编辑显示我正在尝试编写的模块。
【解决方案2】:

正在寻找一种优雅的方式来使用 PUT 将 s3 文件传输到 s3 签名的 url。我发现的大多数示例都是使用 PUT({body : data})。我遇到了一个建议,将数据读取到可读流中,然后将其通过管道传输到 PUT。但是我仍然不喜欢将大文件加载到内存中然后将它们分配给 put 流的概念。管道读取到写入在内存和性能方面总是更好。由于 s3.getObject().createReadStream() 返回一个支持管道的请求对象,我们需要做的就是将其正确地通过管道传递给公开写入流的 PUT 请求。

获取对象函数

async function GetFileReadStream(key){  
    return new Promise(async (resolve,reject)=>{  
        var params = {
            Bucket: bucket, 
            Key: key
            };
        var fileSize = await  s3.headObject(params)
        .promise()
        .then(res => res.ContentLength);
        resolve( {stream : s3.getObject(params).createReadStream(),fileSize});
    });
}

放置对象函数

const request = require('request');
async function putStream(presignedUrl,readStream){
    return new Promise((resolve,reject)=>{
        var putRequestWriteStream =  request.put({url:presignedUrl,headers:{'Content-Type':'application/octet-stream','Content-Length':readStream.fileSize  }});
        putRequestWriteStream.on('response', function(response) {           
            var etag = response.headers['etag'];
            resolve(etag); 
            })
            .on('end', () => 
                console.log("put done"))
        readStream.stream.pipe(putRequestWriteStream);
    });
}

这适用于非常小的内存占用。享受吧。

【讨论】:

    猜你喜欢
    • 2019-01-27
    • 1970-01-01
    • 2021-01-30
    • 2022-01-27
    • 2019-01-30
    • 1970-01-01
    • 2020-05-26
    • 2015-08-26
    • 2021-08-18
    相关资源
    最近更新 更多