如何确定对象是否存在 AWS S3 Node.JS sdk

我需要使用 AWS SDK 检查一个文件是否存在:

var params = {
Bucket: config.get('s3bucket'),
Key: path
};


s3.getSignedUrl('getObject', params, callback);

它可以工作,但问题是当对象不存在时,回调函数(带有参数 err 和 URL)不返回错误,当我试图访问 URL 时,它会显示“ NoSuchObject”。

当对象不存在时,这个 getSignedUrl方法不应该返回一个错误对象吗?如何确定对象是否存在?我真的需要在返回的 URL 上打电话吗?

90162 次浏览

在创建签名 URL 之前,您需要检查文件是否直接从 bucket 中存在。一种方法是请求 HEAD 元数据。

// Using callbacks
s3.headObject(params, function (err, metadata) {
if (err && err.name === 'NotFound') {
// Handle no object on cloud here
} else if (err) {
// Handle other errors here....
} else {
s3.getSignedUrl('getObject', params, callback);
// Do stuff with signedUrl
}
});


// Using async/await
try {
await s3.headObject(params).promise();
const signedUrl = s3.getSignedUrl('getObject', params);
// Do stuff with signedUrl
} catch (error) {
if (error.name === 'NotFound') { // Note with v3 AWS-SDK use error.code
// Handle no object on cloud here...
} else {
// Handle other errors here....
}
}

像这样使用 getObject方法:

var params = {
Bucket: config.get('s3bucket'),
Key: path
};
s3.getObject(params, function(err, data){
if(err) {
console.log(err);
}else {
var signedURL = s3.getSignedUrl('getObject', params, callback);
console.log(signedURL);
}
});

您还可以将 waitFor方法与状态 objectExists一起使用,这将在内部使用 S3.headObject()

var params = {
Bucket: config.get('s3bucket'),
Key: path
};
s3.waitFor('objectExists', params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else     console.log(data);           // successful response
});

使用 headObject方法

AWS.config.update({
accessKeyId: "*****",
secretAccessKey: "****",
region: region,
version: "****"
});
const s3 = new AWS.S3();


const params = {
Bucket: s3BucketName,
Key: "filename" //if any sub folder-> path/of/the/folder.ext
}
try {
await s3.headObject(params).promise()
console.log("File Found in S3")
} catch (err) {
console.log("File not Found ERROR : " + err.code)
}

由于参数是常量,所以在 const中使用它的最佳方法是。如果在 s3中没有找到该文件,则抛出错误 NotFound : null

如果希望在 bucket 中应用任何操作,则必须更改 AWS 中相应 bucket 中 CORS Configuration的权限。用于更改权限 Bucket->permission->CORS Configuration和添加此代码。

<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

更多有关 CORS 配置的信息: https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html

Synchronous call on S3 in Nodejs instead of asynchronous call using Promise

var request = require("request");
var AWS = require("aws-sdk");


AWS.config.update({
accessKeyId: "*****",
secretAccessKey: "********"
});




const s3 = new AWS.S3();




var response;


function initialize(bucket,key) {
// Setting URL and headers for request
const params = {
Bucket: bucket,
Key: key
};
// Return new promise
return new Promise(function(resolve, reject) {
s3.headObject(params, function(err, resp, body) {
if (err) {
console.log('Not Found : ' + params.Key );
reject(params.Key);
} else {
console.log('Found : ' + params.Key );
resolve(params.Key);
}
})
})
}


function main() {


var foundArray = new Array();
var notFoundArray = new Array();
for(var i=0;i<10;i++)
{
var key = '1234'+ i;
var initializePromise = initialize('****',key);
initializePromise.then(function(result) {
console.log('Passed for : ' + result);
foundArray.push(result);
console.log (" Found Array : "+ foundArray);
}, function(err) {
console.log('Failed for : ' + err);
notFoundArray.push(err);
console.log (" Not Found Array : "+ notFoundArray);
});
}




}


main();

同步放入操作

var request = require("request");
var AWS = require("aws-sdk");


AWS.config.update({
accessKeyId: "*****",
secretAccessKey: "***"
});




const s3 = new AWS.S3();




var response;


function initialize(bucket,key) {
// Setting URL and headers for request
const params = {
Bucket: bucket,
Key: key
};
// Return new promise
return new Promise(function(resolve, reject) {
s3.putObject(params, function(err, resp, body) {
if (err) {
reject();
} else {
resolve();
}
})
})
}


function main() {


var promiseArray = [];
var prefix = 'abc/test/';
for(var i=0;i<10;i++)
{
var key = prefix +'1234'+ i;
promiseArray[i] = initialize('bucket',key);
promiseArray[i].then(function(result) {
console.log (" Successful ");
}, function(err) {
console.log (" Error ");
});
}




console.log('Promises ' + promiseArray);




Promise.all(promiseArray).then(function(values) {
console.log("******TESTING****");
});




}




main();

无故障同步操作

var request = require("request");
var AWS = require("aws-sdk");


AWS.config.update({
accessKeyId: "*******",
secretAccessKey: "***********"
});




const s3 = new AWS.S3();




var response;


function initialize(bucket,key) {
// Setting URL and headers for request
const params = {
Bucket: bucket,
Key: key
};
// Return new promise
return new Promise(function(resolve, reject) {
s3.headObject(params, function(err, resp, body) {
if (err) {
resolve(key+"/notfound");
} else{
resolve(key+"/found");
}
})
})
}


function main() {


var foundArray = new Array();
var notFoundArray = new Array();
var prefix = 'abc/test/';
var promiseArray = [];
try{
for(var i=0;i<10;i++)
{
var key = prefix +'1234' + i;
console.log("Key : "+ key);
promiseArray[i] = initialize('bucket',key);
promiseArray[i].then(function(result) {
console.log("Result : " + result);
var temp = result.split("/");
console.log("Temp :"+ temp);
if (temp[3] === "notfound")
{
console.log("NOT FOUND");
}else{
console.log("FOUND");
}


}, function(err) {
console.log (" Error ");
});
}


Promise.all(promiseArray).then(function(values) {
console.log("^^^^^^^^^^^^TESTING****");
}).catch(function(error) {
console.error(" Errro : "+ error);
});








}catch(err){
console.log(err);
}




}


main();

The simplest solution without try/catch block.

const exists = await s3
.headObject({
Bucket: S3_BUCKET_NAME,
Key: s3Key,
})
.promise()
.then(
() => true,
err => {
if (err.code === 'NotFound') {
return false;
}
throw err;
}
);

到2022年2月,使用 JavaScriptV3SDK 的正确方法是 使用 HeadObjectCommand

Note: I'm using TypeScript here with explicit typings, but you can remove those explicit typings when you refactor the code...they're just to show the AWS types in use.

import {
S3Client,
HeadObjectCommand, HeadObjectCommandInput, HeadObjectCommandOutput,
} from '@aws-sdk/client-s3';


function async existsInS3(
client: S3Client,
bucket: string,
key: string,
): Promise<boolean> {
try {
const bucketParams: HeadObjectCommandInput = {
Bucket: bucket,
Key: key,
};
const cmd = new HeadObjectCommand(bucketParams);
const data: HeadObjectCommandOutput = await client.send(cmd);


// I always get 200 for my testing if the object exists
const exists = data.$metadata.httpStatusCode === 200;
return exists;
} catch (error) {
if (error.$metadata?.httpStatusCode === 404) {
// doesn't exist and permission policy includes s3:ListBucket
return false;
} else if (error.$metadata?.httpStatusCode === 403) {
// doesn't exist, permission policy WITHOUT s3:ListBucket
return false;
} else {
// some other error
...log and rethrow if you like
}
}
}

如果查看上面链接的 HeadObjectCommand文档的 Permission 部分,您会注意到 它提到了403和404回复:

此操作需要相关的读取对象(或版本)权限。有关详细信息,请参阅在策略中指定权限。如果请求的对象不存在,Amazon S3返回的错误取决于您是否也具有 S3: ListBucket 权限。

If you have the s3:ListBucket permission on the bucket, Amazon S3 returns an HTTP status code 404 ("no such key") error.

If you don’t have the s3:ListBucket permission, Amazon S3 returns an HTTP status code 403 ("access denied") error.

我不知道这些错误响应是否可能来自其他错误 钥匙的不存在。

CORS

我还必须在桶的 CORS 权限的 AllowedMethods部分中添加 HEAD:

"AllowedMethods": [
"GET",
"PUT",
"HEAD"
],

另一种在其他答案中没有提到的方法是使用 listObjectsV2命令。

我不知道这是否是 好多了headObject方法,但它不依赖于404响应和尝试/捕获。

诀窍是设置 Prefix参数以匹配您正在寻找的键。

async function checkObjectExists(bucket, key) {
const data = await s3
.listObjectsV2({
Bucket: bucket,
MaxKeys: 1, // We should only get 1 object, or 0.
Prefix: key, // Limit the response to objects whose key starts with the given key.
})
.promise();
return data.Contents.length > 0;
}


这是基于 AWS SDK for JavaScript v3的。

import {
S3Client,
} from "@aws-sdk/client-s3";


const s3Client = new S3Client({
region: "your-aws-region"
});


const checkIfFileExist = async () => {
try {
const response = await s3Client.send(
new HeadObjectCommand({
Bucket: "your-bucket",
Key: "your-file.txt"
})
);
return true;
} catch (error) {
if (error.httpStatusCode === 404) return false;
}
};


const doSomeProcess = async () => {
const fileExist = await checkIfFileExist();
console.log(fileExist);
}