Подавать файл индекса вместо запроса на загрузку - PullRequest
0 голосов
/ 13 января 2019

Мой сайт размещен на S3 с CloudFront в качестве CDN, и мне нужно, чтобы эти два URL работали одинаково и служили файлу index.html в каталоге:

example.com/directory example.com/directory/

Тот, у которого / в конце, неверно предлагает браузеру загрузить файл нулевого байта со случайным хешем для имени файла. Без косой черты он возвращает мою страницу 404.

Как получить оба пути для доставки файла index.html в каталоге?

Если есть способ, которым я "должен" сделать это, прекрасно! Это то, на что я надеюсь, но если нет, то, вероятно, попробую использовать Lambda @ Edge для перенаправления. В любом случае, мне это нужно для некоторых других ситуаций, поэтому некоторые инструкции о том, как выполнить перенаправление 301 или 302 из Lambda @ Edge, также будут полезны:)

Обновление (согласно комментарию Джона Хэнли)

curl -i https://www.example.com/directory/

HTTP/2 200 
content-type: application/x-directory
content-length: 0
date: Sat, 12 Jan 2019 22:07:47 GMT
last-modified: Wed, 31 Jan 2018 00:44:16 GMT
etag: "[id]"
accept-ranges: bytes
server: AmazonS3
x-cache: Miss from cloudfront
via: 1.1 [id].cloudfront.net (CloudFront)
x-amz-cf-id: [id]

Обновление

CloudFront имеет один набор поведения: пересылка http на https и отправка запросов на S3. На вкладке ошибок также имеется маршрут ошибки 404.

Ответы [ 2 ]

0 голосов
/ 19 января 2019

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'`);
    }

};
0 голосов
/ 13 января 2019

Этот тип поведения обычно контролируется / вызывается данными заголовка HTTP (s), в частности, Content-Type , который получает ваш клиент.

Проверьте заголовок и попробуйте настроить то, что возвращается с вашего сервера. Это должно привести к вашему решению.

  1. В Chrome перейдите по URL-адресу, щелкните правой кнопкой мыши и выберите «Проверить», чтобы открыть инструменты разработчика.
  2. Выберите вкладку Сеть.
  3. Перезагрузите страницу, выберите любой HTTP-запрос на левой панели, и заголовки HTTP будут отображены на правой панели.
...