S3/Cloudfront: 如何列出存储桶中文件夹的内容
S3/Cloudfront: how to list a folder's contents in a bucket
我编写了一个方法来签署 URL 以读取通过 Cloudfront 访问的 S3 存储桶:
private HTTPResponse signURL(String endpoint) {
String keyPairId = 'keyPairId';
String secret = 'SOME_SECRET';
String method = 'GET';
Datetime dt = Datetime.now();
Long l = dt.getTime();
Long expiryLong = (l / 1000) + 3600;
String expiry = String.valueOf(expiryLong);
String policy = policy('http://' + cfhost + '/' + endpoint, expiry);
String policyEnc = EncodingUtil.base64Encode(Blob.valueOf(policy));
String rPolicy = cfReplace(policyEnc);
Blob mac = Crypto.generateMac('HMACSHA1',
Blob.valueOf(rPolicy),
Blob.valueOf(secret));
String signature = cfReplace(EncodingUtil.base64Encode(mac));
HttpRequest req = new HttpRequest();
req.setMethod(method);
req.setEndpoint('http://' + cfhost + '/' + endpoint + '?Policy=' +
policyEnc + '&Signature=' + signature + '&Key-Pair-Id=' +
keyPairId);
Http http = new Http();
HTTPResponse res = http.send(req);
return res;
}
现在,如果端点设置为 ''
,我的方法可以正常工作。如果我将文件夹名称放在端点中(如 00Q17000008LRcAEAW/*
),我会在 XML 响应中收到一堆错误。
XMLNode[ELEMENT,Error,null,null,null,[XMLNode[ELEMENT,Code,null,null,null,[XMLNode[TEXT,null,null,null,null,null,NoSuchKey,]],null,], XMLNode[ELEMENT,Message,null,null,null,[XMLNode[TEXT,null,null,null,null,null,The specified key does not exist.,]],null,], XMLNode[ELEMENT,Key,null,null,null,[XMLNode[TEXT,null,null,null,null,null,00Q17000008LRcAEAW/*,]],null,], XMLNode[ELEMENT,RequestId,null,null,null,[XMLNode[TEXT,null,null,null,null,null,some_req_id,]],null,], XMLNode[ELEMENT,HostId,null,null,null,[XMLNode[TEXT,null,null,null,null,null,some_host_id,]],null,]],null,]
我无法列出整个存储桶,因为它对于 1000 键的限制来说太大了。如何列出文件夹?
查看列表对象的 S3 文档,V1 and V2 了解 S3 的期望。
简而言之,您必须在查询字符串中提供前缀和分隔符(几乎总是 /
),而不是路径。对于对象列表,路径始终是存储桶的根,例如:
https://dxxxexample.cloudfront.net/?delimiter=/&prefix=00Q17000008LRcAEAW/&...
这也意味着,如果您为发行版定义了 default root object,则不能通过发行版也拉取目录列表。在这种情况下,您需要第二次分发,或者需要直接从 S3 获取对象列表。
无论如何,请记住对象列表相对昂贵,超过 GET
请求价格的 10 倍,因此如果缓存响应有意义,则使用 CloudFront 获取它们可能有意义,或者对于对象列表,您可能想做一些完全不同的事情。我一直在推出一个使用 S3 事件通知、Lambda 和 RDS 的设置,以将所有对象及其元数据存储在一个单独的近实时数据库中,我可以在其中获得更快、更完整的列表,而无需成本(和我可以根据元数据搜索对象)。
我编写了一个方法来签署 URL 以读取通过 Cloudfront 访问的 S3 存储桶:
private HTTPResponse signURL(String endpoint) {
String keyPairId = 'keyPairId';
String secret = 'SOME_SECRET';
String method = 'GET';
Datetime dt = Datetime.now();
Long l = dt.getTime();
Long expiryLong = (l / 1000) + 3600;
String expiry = String.valueOf(expiryLong);
String policy = policy('http://' + cfhost + '/' + endpoint, expiry);
String policyEnc = EncodingUtil.base64Encode(Blob.valueOf(policy));
String rPolicy = cfReplace(policyEnc);
Blob mac = Crypto.generateMac('HMACSHA1',
Blob.valueOf(rPolicy),
Blob.valueOf(secret));
String signature = cfReplace(EncodingUtil.base64Encode(mac));
HttpRequest req = new HttpRequest();
req.setMethod(method);
req.setEndpoint('http://' + cfhost + '/' + endpoint + '?Policy=' +
policyEnc + '&Signature=' + signature + '&Key-Pair-Id=' +
keyPairId);
Http http = new Http();
HTTPResponse res = http.send(req);
return res;
}
现在,如果端点设置为 ''
,我的方法可以正常工作。如果我将文件夹名称放在端点中(如 00Q17000008LRcAEAW/*
),我会在 XML 响应中收到一堆错误。
XMLNode[ELEMENT,Error,null,null,null,[XMLNode[ELEMENT,Code,null,null,null,[XMLNode[TEXT,null,null,null,null,null,NoSuchKey,]],null,], XMLNode[ELEMENT,Message,null,null,null,[XMLNode[TEXT,null,null,null,null,null,The specified key does not exist.,]],null,], XMLNode[ELEMENT,Key,null,null,null,[XMLNode[TEXT,null,null,null,null,null,00Q17000008LRcAEAW/*,]],null,], XMLNode[ELEMENT,RequestId,null,null,null,[XMLNode[TEXT,null,null,null,null,null,some_req_id,]],null,], XMLNode[ELEMENT,HostId,null,null,null,[XMLNode[TEXT,null,null,null,null,null,some_host_id,]],null,]],null,]
我无法列出整个存储桶,因为它对于 1000 键的限制来说太大了。如何列出文件夹?
查看列表对象的 S3 文档,V1 and V2 了解 S3 的期望。
简而言之,您必须在查询字符串中提供前缀和分隔符(几乎总是 /
),而不是路径。对于对象列表,路径始终是存储桶的根,例如:
https://dxxxexample.cloudfront.net/?delimiter=/&prefix=00Q17000008LRcAEAW/&...
这也意味着,如果您为发行版定义了 default root object,则不能通过发行版也拉取目录列表。在这种情况下,您需要第二次分发,或者需要直接从 S3 获取对象列表。
无论如何,请记住对象列表相对昂贵,超过 GET
请求价格的 10 倍,因此如果缓存响应有意义,则使用 CloudFront 获取它们可能有意义,或者对于对象列表,您可能想做一些完全不同的事情。我一直在推出一个使用 S3 事件通知、Lambda 和 RDS 的设置,以将所有对象及其元数据存储在一个单独的近实时数据库中,我可以在其中获得更快、更完整的列表,而无需成本(和我可以根据元数据搜索对象)。