AFAICT the correct way to do this as of February 2022, with JavaScript V3 SDK is
to use the 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
}
}
}
If you look in the Permissions section of the HeadObjectCommand
documentation linked above, you'll notice
it mentions the 403 and 404 responses:
You need the relevant read object (or version) permission for this operation. For more information, see Specifying Permissions in a Policy. If the object you request does not exist, the error Amazon S3 returns depends on whether you also have the s3:ListBucket permission.
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.
I don't know if these error responses could stem from other errors in addition
to the non-existence of the key.
CORS
I also had to add HEAD
in the AllowedMethods
section of CORS permissions on the bucket:
"AllowedMethods": [
"GET",
"PUT",
"HEAD"
],