如何检查 Amazon S3 中的文件是否存在,使用 Node.js。

7
我正在研究如何在S3上执行fs.exists()的相当操作。
我成功获取了存储桶的内容,但我无法弄清楚如何向S3询问特定文件是否存在于存储桶中(因为文件太多,我不想下载整个文件列表并在客户端进行检查)。
参考:AWS2JS S3.GET文档
var s3 = require('aws2js').load('s3', appConfig.awsAccessKeyId, appConfig.awsSecretAccessKey);  
s3.setBucket(appConfig.awsBucketName);

            var folder = encodeURI('reports');
            var url = '?prefix=' + folder;

            s3.get(url,{Contents: null, Key: 'reports/emot_cat_r1180341142.png'},'xml', function (error, data) {
                console.log("Error",error);
                console.log("Data",data);
                true.should.be.true;
                done();
            });

输出结果如下:

输出

{名称:'umusergen',前缀:'reports',标记:{},MaxKeys: '1000',IsTruncated:'false',内容:[ {键:'reports /', LastModified:'2013-06-16T17:44:25.000Z', ETag:'“d41d8cd98f00b204e9800998ecf8427e”', 尺寸:'0', 所有者:[Object], 存储类:'STANDARD'}, {键:'reports / emot_cat_r1180341142.png', LastModified:'2013-06-16T23:18:59.000Z', ETag:'“0b04aa9146d36a447019b1aa94be7eb3”', 尺寸:'26374', 所有者:[Object], 存储类:'STANDARD'}, {键:'reports / polarity_r1180341142.png', LastModified:'2013-06-16T23:19:00.000Z', ETag:'“22fd521e0a5e858040082d0d47078532”', 尺寸:'23091', 所有者:[Object], 存储类:'STANDARD'}, {键:'reports / wordcloud_r1180341142.png', LastModified:'2013-06-16T23:19:07.000Z', ETag:'“9f7ee9d2fdce5f460b2c42444edd6efc”', 尺寸:'167164', 所有者:[Object], 存储类:'STANDARD'}],'@':{xmlns:{xmlns:http://s3.amazonaws.com/doc/2006-03-01/ '}}}

"{Contents:null,Key:'[file path/name]'}"是我尝试解释上面引用的API说明。

如您所见,它只列举了存储桶的内容,但我需要API调用来检查特定文件是否存在。

有人能帮忙吗? 我对所有这些都还很陌生。

2个回答

11

你必须通过发送HEAD请求来使用HTTP方式进行操作。如果文件不存在会触发404错误。以下是一个简单的实现:

var s3 = require('aws2js').load('s3', process.env.AWS_ACCEESS_KEY_ID, process.env.AWS_SECRET_ACCESS_KEY)

s3.setBucket(process.env.AWS2JS_S3_BUCKET)

s3.head(process.argv[2], function (err, res) {
    if (err) {
        console.log(err)
        return
    }
    console.log(res)
})

为了测试目的,可以使用以下方式调用:

node s3-check.js file/path.foo

示例:

node s3-check.js foo1.png
{ 'x-amz-id-2': 'BU8rLC35oZdNLh4TkE9Y5+czR5r9hg7kl/EbhkxUF+cA94F41knI2YNs/YG1acQg',
  'x-amz-request-id': '7714B364EC1A27B2',
  date: 'Mon, 17 Jun 2013 06:42:52 GMT',
  'last-modified': 'Tue, 28 May 2013 13:18:12 GMT',
  etag: '"2830931876c37237ae98458a99e86d85"',
  'accept-ranges': 'bytes',
  'content-type': 'image/png',
  'content-length': '1165',
  server: 'AmazonS3' }

node s3-check.js foo0.png
{ [Error: API error with HTTP Code: 404]
  headers:
   { 'x-amz-request-id': '96841B9C0BC5E66D',
     'x-amz-id-2': 'ZMZH9bkrR6nhDkWK1hM+qm0dlzBOYhOZhVyT3nKlMuZgPag//5EhfBuAHZq+9ZRm',
     'content-type': 'application/xml',
     'transfer-encoding': 'chunked',
     date: 'Mon, 17 Jun 2013 06:43:53 GMT',
     server: 'AmazonS3' },
  code: 404 }

你知道在Mocha中运行awsjs是否存在问题吗?当我在describe(it())之外运行代码时,它可以正常工作。但是当我将代码包装在测试中时,s3回调都没有返回。我会将这个问题单独提出来。 - metalaureate
我在这里提出了一个后续问题:http://stackoverflow.com/questions/17151467/node-js-awsjs-s3-head-function-does-not-return-in-mocha-test-framework - metalaureate
抱歉,忽略那个与编程无关的问题。 - metalaureate
想说一些关于缺失的done的事情,但人们已经跳进来了。一些指针:有时我会忘记应该将done()传递给it(),但是带有超时的失败测试是一个很好的指示器。否则,在我的情况下,如果调用已经存在但没有传递给it(),jslint会报告调用未定义的done()。我建议使用一些静态代码分析工具。对于琐碎的错误可以减轻很多压力。 - SaltwaterC
谢谢 - 我将来会尝试这个。 - metalaureate

7
现有的答案已经过时了,有更好的方法可以做到这一点。通过使用aws-sdk模块,您可以获得一个良好的API来完成此操作。 aws-sdk有一个名为headObject的函数来查看文件的元数据。以下是示例用法。
import Promise from 'bluebird'
import AWS from 'aws-sdk'

AWS.config.accessKeyId = Config.Credentials.AWS.accessKeyId
AWS.config.secretAccessKey = Config.Credentials.AWS.secretAccessKey

const s3 = new AWS.S3
Promise.promisifyAll(s3)

const getFileFromS3 = async ({ Bucket, Key })=> {
  try {
    const result = await S3.headObjectAsync({ Bucket, Key })
    console.log(result)
    /* Output:
      { AcceptRanges: 'bytes',
          LastModified: 'Mon, 16 Jan 2017 07:30:19 GMT',
          ContentLength: '6',
          ETag: '"b1946ac92492d2347c6235b4d2611184"',
          ContentType: 'text/plain',
          Metadata: {} }
    */
  } catch (error) {
    if (error.statusCode === 404) console.log('File Not Found')
    console.error('Unexpected Error', error)
  }
}

你能澄清一下 fs.exists() 的等效位置在哪里吗?如果键不存在会发生什么?它会运行 catch 部分吗? - Arkanoid
是的,你说得对。自从写了那篇文章后,我已经转向使用ES6,所以我重写了它,并添加了一些可能更明确的代码行。 - Tim

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