Как сохранить путь маршрута SPA в браузере с помощью AWS CloudFront

На днях я заметил очень раздражающее поведение на моем личном сайте, который я создал с помощью Angular. Когда я ввожу свое доменное имя в строке URL браузера.

я получаю перенаправление на elbanhawy.com/home и вижу, как загружается главная страница моего сайта. Это не раздражающее поведение, это ожидаемая часть. Случайно я обнаружил, что если я попытаюсь перезагрузить эту страницу или ввести определенный путь на моем сайте, например elbanhawy.com/blog, я получу ответ Access Denied от AWS!

Что здесь происходит???

Это может шокировать любого, кто никогда раньше не разворачивал SPA, такие как React, Vue и Angular на AWS S3 и CloudFront, поэтому давайте посмотрим, как я решил эту проблему.

Шаг 1: Контрольный список для отладки

Проверка политик ведра S3 и конфигураций CF Origins и OAI

Мой сайт angular размещен на S3 bucket, который не является публичным. Мой дистрибутив CloudFront обслуживает содержимое ведра S3, поэтому мои политики ведра S3 должны явно разрешать моему дистрибутиву CloudFront доступ ко всему содержимому внутри ведра. Давайте посмотрим:

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E3LLNG3QXXXXX"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::my-angular-website/*"
        }
    ]
}
Вход в полноэкранный режим Выход из полноэкранного режима

Приведенная выше политика ведра явно позволяет моему CloudFront OAI, который я связал с моим дистрибутивом CloudFront, получить доступ/получить все объекты внутри ведра S3. Я обращаю внимание на OAI ID E3LLNG3QXXXXX, который понадобится мне позже.
Я дважды проверяю на вкладке Origins дистрибутива CloudFront, указан ли мой S3 bucket в качестве источника.

Я вижу, что оно там есть, поэтому выбираю его и нажимаю «Редактировать», чтобы увидеть детали его конфигурации:

Я убеждаюсь, что в разделе «Доступ к ведру S3» выбрана опция «Да, использовать OAI». 

Теперь я обращаю внимание на имя OAI, выбранное выше. Я перехожу в консоль CloudFront (CF/Security/Origin access identities), чтобы увидеть мои перечисленные OAI. Помните идентификатор OAI, который я указал в политике ведра S3? Теперь мне нужно убедиться, что он присутствует в списке.

Я вижу, что он есть, поэтому я могу с уверенностью предположить, что дистрибутив CloudFront, обслуживающий мой сайт, имеет правильный доступ к моему ведру S3.

Хорошо… Так что же еще может быть не так?

Шаг 2: Решение

На этом этапе я ломаю голову и безуспешно пытаюсь прочесть бесчисленные документы AWS в поисках подсказок. Но потом я замечаю интересную вкладку на странице распространения моего CloudFront.

Если подумать, когда я ввожу свой корневой домен, я не получаю никаких ошибок. Только когда я перезагружаю или включаю определенный маршрут в URL, я получаю ошибку Access Denied, что переводится как код ошибки 403.

Поэтому я решил нажать «Создать пользовательский ответ на ошибку» и добавить запись:

Я выбираю 403:Forbidden из списка кодов ошибок, затем выбираю «Yes» для Customize error response и затем, и это критическая часть, я ввожу «/index.html» в качестве пути к странице ответа и 200: OK в качестве кода ответа HTTP.

Теперь, если я ввожу URL-адрес пути к блогу в браузере и нажимаю Enter, мне открывается нужная страница без какой-либо ошибки Access Denied, даже если я перезагружаю страницу!

Примечание: если у вас несколько дистрибутивов CloudFront для вашего сайта S3, вам нужно выполнить эти шаги для каждого из них. Например, у меня был отдельный дистрибутив для моего поддомена www, и мне пришлось применить решение для него, а также для дистрибутива корневого домена (elbanhawy.com).

Шаг 3: Отражение

Я решил проблему, но все еще не хватает четкого объяснения того, почему эта ошибка Access Denied появилась в первую очередь.

Это можно объяснить тем, как ведут себя ведра S3 в ответ на запросы. S3 не понимает маршрутов. Ведро S3 похоже на сервер, который ожидает путь к определенному файлу, хранящемуся в нем. Например, я могу быть более явным и добавить /index.html в конце url моего домена, и я все равно получу домашнюю страницу. S3 понимает это, потому что ищет файл с именем index.html в ведре и возвращает его.

Изначально, когда я вводил адрес своего домена elbanhawy.com, из-за моих настроек CloudFront автоматически добавлял /index.html к запросу, который он пересылал в ведро S3, что S3 понимал и возвращал мой файл index.html, содержащий ссылки на мой скомпилированный код angular. При загрузке в браузере ангулярное приложение приняло на себя управление, и ангулярный маршрутизатор начал действовать.

Однако, когда я перезагружаю страницу или ввожу маршрут в url, CloudFront пересылает запрос на S3 как есть, и S3 пытается найти буквальное соответствие для файла с тем же именем маршрута. Например, когда я пробовал elbanhawy.com/blog до исправления, S3 пытался искать файл с именем blog, который не существует, поэтому он возвращает ошибку. Поскольку я изначально не указал, как ошибки должны обрабатываться CloudFront, браузеру возвращалась ошибка Access Denied.

Решение, приведенное выше, изменило поведение ошибки по умолчанию, чтобы всегда возвращать файл index.html при возникновении этой ошибки, поэтому сайт angular всегда возвращается, а маршрутизатор angular по-прежнему получает доступ к маршруту в URL и может показать мне правильную страницу.

За другими советами и мнениями по облачным технологиям и веб-разработке следите за мной в Twitter @adham_benhawy.

Оцените статью
devanswers.ru
Добавить комментарий