S3 предлагает автоматическое индексирование документов, только если вы включили и используете функции хостинга веб-сайта корзины, указывая на конечную точку хоста веб-сайта корзины ${bucket}.s3-website.${region}.amazonaws.com
, а не на общую конечную точку REST корзины * 1002. *.
Конечные точки веб-сайта и конечные точки REST имеют многочисленные отличия , включая эту.
Причина, по которой вы видите эти 0-байтовые файлы для ключей объектов, оканчивающихся на /
, заключается в том, что вы создаете объекты папок в корзине с помощью консоли S3 или другой утилиты, которая фактически создает 0-байтовые объекты. Они не нужны, если в папках есть объекты «внутри», но это единственный способ отобразить пустую папку в консоли S3, в которой объект с именем foo/
отображается как папка с именем foo
, даже если нет других объектов с префиксом ключа foo/
. Это часть визуальной эмуляции иерархии папок в консоли, хотя объекты в S3 никогда не бывают «в» папках.
Если по какой-то причине вам нужно использовать конечную точку REST - например, если вы не хотите делать корзину общедоступной - тогда вам понадобится два триггера Lambda @ Edge в CloudFront, чтобы эмулировать эту функцию довольно близко.
Триггер Origin Request может проверять и изменять запросы после проверки кэша CloudFront, перед тем как запрос будет отправлен в источник. Мы используем это для проверки пути, заканчивающегося на /
и добавляем index.html
, если найдем это.
Триггер Origin Response может проверять и потенциально изменять ответы, прежде чем они будут записаны в кэш CloudFront. Триггер исходного ответа также может проверять исходный запрос, предшествующий запросу, сгенерировавшему ответ. Мы используем это, чтобы проверить, является ли ответ ошибкой. Если это так, и исходный запрос не , по-видимому, относится к документу индекса или файлу (в частности, после последней косой черты в пути, «файл» имеет как минимум один символ, за которым следует точка, за которой следует по крайней мере еще один символ - и если это так, то это, вероятно, «файл»). Если это не одна из этих вещей, мы перенаправляем на исходный путь и добавляем окончательный /
.
Триггеры исходного запроса и ответа источника запускают только при пропадании кэша. При попадании в кэш ни один из триггеров не срабатывает, потому что они находятся на исходной стороне CloudFront - обратной стороне кеша. Запросы, которые можно обслуживать из кэша, обслуживаются из кэша, поэтому триггеры не вызываются.
Ниже приведена функция Lambda @ Edge, написанная в Node.js 8.10. Эта одна лямбда-функция изменяет свое поведение так, что она ведет себя как исходный запрос или исходный ответ, в зависимости от контекста. После публикации версии в Lambda свяжите ARN этой версии с настройками поведения CloudFront Cache как и как запрос источника и триггер ответа источника.
'use strict';
// combination origin-request, origin-response trigger to emulate the S3
// website hosting index document functionality, while using the REST
// endpoint for the bucket
// https://stackoverflow.com/a/54263794/1695906
const INDEX_DOCUMENT = 'index.html'; // do not prepend a slash to this value
const HTTP_REDIRECT_CODE = '302'; // or use 301 or another code if desired
const HTTP_REDIRECT_MESSAGE = 'Found';
exports.handler = (event, context, callback) => {
const cf = event.Records[0].cf;
if(cf.config.eventType === 'origin-request')
{
// if path ends with '/' then append INDEX_DOCUMENT before sending to S3
if(cf.request.uri.endsWith('/'))
{
cf.request.uri = cf.request.uri + INDEX_DOCUMENT;
}
// return control to CloudFront, to send request to S3, whether or not
// we modified it; if we did, the modified URI will be requested.
return callback(null, cf.request);
}
else if(cf.config.eventType === 'origin-response')
{
// is the response 403 or 404? If not, we will return it unchanged.
if(cf.response.status.match(/^40[34]$/))
{
// it's an error.
// we're handling a response, but Lambda@Edge can still see the attributes of the request that generated this response; so, we
// check whether this is a page that should be redirected with a trailing slash appended. If it doesn't look like an index
// document request, already, and it doesn't end in a slash, and doesn't look like a filename with an extension... we'll try that.
// This is essentially what the S3 web site endpoint does if you hit a nonexistent key, so that the browser requests
// the index with the correct relative path, except that S3 checks whether it will actually work. We are using heuristics,
// rather than checking the bucket, but checking is an alternative.
if(!cf.request.uri.endsWith('/' + INDEX_DOCUMENT) && // not a failed request for an index document
!cf.request.uri.endsWith('/') && // unlikely, unless this code is modified to pass other things through on the request side
!cf.request.uri.match(/[^\/]+\.[^\/]+$/)) // doesn't look like a filename with an extension
{
// add the original error to the response headers, for reference/troubleshooting
cf.response.headers['x-redirect-reason'] = [{ key: 'X-Redirect-Reason', value: cf.response.status + ' ' + cf.response.statusDescription }];
// set the redirect code
cf.response.status = HTTP_REDIRECT_CODE;
cf.response.statusDescription = HTTP_REDIRECT_MESSAGE;
// set the Location header with the modified URI
// just append the '/', not the "index.html" -- the next request will trigger
// this function again, and it will be added without appearing in the
// browser's address bar.
cf.response.headers['location'] = [{ key: 'Location', value: cf.request.uri + '/' }];
// not strictly necessary, since browsers don't display it, but remove the response body with the S3 error XML in it
cf.response.body = '';
}
}
// return control to CloudFront, with either the original response, or
// the modified response, if we modified it.
return callback(null, cf.response);
}
else // this is not intended as a viewer-side trigger. Throw an exception, visible only in the Lambda CloudWatch logs and a 502 to the browser.
{
return callback(`Lambda function is incorrectly configured; triggered on '${cf.config.eventType}' but expected 'origin-request' or 'origin-response'`);
}
};