Срок действия запроса истек при использовании S3 с Active Storage

Я впервые использую ActiveStorage. В разработке все работает нормально, но в производстве (Heroku) мои изображения исчезают без причины.

В первый раз они показывали нормально, но теперь изображение не отображается. В консоли я вижу такую ​​ошибку:

GET https://XXX.s3.amazonaws.com/variants/Q7MZrLyoKKmQFFwMMw9tQhPW/XXX 403 (Forbidden)

Если я попытаюсь посетить этот URL напрямую, я получу XML

<Error>
  <Code>AccessDenied</Code>
  <Message>Request has expired</Message>
  <X-Amz-Expires>300</X-Amz-Expires>
  <Expires>2018-07-24T13:48:25Z</Expires>
  <ServerTime>2018-07-24T15:25:37Z</ServerTime>
  <RequestId>291D41FAC6708334</RequestId>      
  <HostId>lEVGuwA6Hvlm/i40PeXaje9SEBYks9+uk6DvBs=</HostId>
</Error>

Это то, что я имею ввиду

<div class="cover" style="background-image: url('<%= rails_representation_path(experience.thumbnail) %>')"></div>

Это то, что есть у меня в модели

def thumbnail
  self.cover.variant(resize: "300x300").processed
end

Проще говоря, я не хочу, чтобы изображения истекали, а всегда были там.

Спасибо


person Manuel Frigerio    schedule 24.07.2018    source источник


Ответы (2)


ActiveStorage не поддерживает ссылку с истекшим сроком действия. Он использует ссылки с истекающим сроком действия (частные) и поддерживает загрузку файлов только как частные в вашем сервисе.

Для меня это тоже было проблемой, и я сделал 2 патча (предостережение) только для S3, одна простая ~ 30 строк, которая переопределяет ActiveStorage для работы только с бессрочными (общедоступными) ссылками, и еще один, который добавляет параметр acl к методам has_one_attached и has_many_attached.

Надеюсь, поможет.

person Dinatih    schedule 25.07.2018
comment
Привет, Динатих, это выглядит великолепно, но я пытаюсь понять это: ActiveStorage не поддерживает ссылку с истекшим сроком действия. Что это обозначает? Мне нужно очень простое: изображения всегда присутствуют, когда люди загружают страницу. Они не истекают, ничего необычного не происходит. Люди заходят на сайт и видят изображения. Почему я не могу загружать общедоступные изображения с помощью ActiveStorage? - person Manuel Frigerio; 25.07.2018
comment
Похоже, ActiveStorage создавался не для этого. То же самое и с производительностью - ссылки на ресурсы создают множество перенаправлений, задержек и затрудняют использование CDN. - person Nick M; 21.08.2019

В вашем вопросе об этом не говорится, но CDN, например AWS CloudFront, часто используется с приложением Rails. Вы, вероятно, захотите сэкономить вычислительную мощность, особенно на Heroku.

Вот что происходит в этом сценарии. Вы визуализируете страницу как обычно, и все изображения запрашиваются с узла ресурсов, которым является CDN, потому что именно так он настроен для интеграции. Его настройка для извлечения всего, что не находит в кеше, из источника, который снова является вашим приложением.

Сначала проходят все запросы изображений. Контроллер ActiveStorage создает для них подписанные URL-адреса, а CDN передает их, но также кэширует.

Теперь возникает проблема. Подписанный URL-адрес по умолчанию истекает через 5 минут, но CDN кэширует обычно намного дольше. Это связано с тем, что обычно вы используете дайджест-активы, то есть они становятся недействительными не по времени, а по имени, при любом изменении.

Решение простое. Увеличьте срок действия подписанного URL-адреса, чтобы он превышал TTL кеша. Теперь кеш удаляет кэшированный подписанный URL-адрес, прежде чем он станет недействительным.

Установите срок действия URL-адреса с помощью ActiveStorage::Service.url_expires_in в 5.2 или непосредственно в Rails.application.config.active_storage.service_urls_expire_in в инициализаторе подробности см. в этом ответе.

Чтобы установить TTL кеша в CloudFront: откройте консоль AWS, выберите распределение, откройте вкладку Поведение, прокрутите вниз до следующих полей:

поля ttl cloudfront

Затем, при желании, сделайте аннулирование, чтобы принудительно повторно кэшировать все содержимое.

Имейте в виду, что существует компромисс безопасности. Если содержимое изображения является частным, то, скорее всего, оно не принадлежит CDN и не должно иметь длительных временных URL-адресов. В этом случае выберите решение, которое полностью исключает вложения из CDN. Ваше приложение должно будет справиться с дополнительной нагрузкой, связанной с подписанием URL-адресов всех прикрепленных ресурсов поверх рендеринга соответствующей страницы.

Кроме того, имейте в виду, что это не обязательно хорошее решение, это скорее обходной путь. С помощью описанной выше настройки вы будете кэшировать перенаправления, и более тяжелые запросы будут напрямую попадать в вашу корзину хранилища. Обычный сценарий для CDN - это большие носители, а не легкие перенаправления. Тем не менее, вы избавляете приложение от обработки большого количества запросов. Следует выяснить, насколько это допустимая оптимизация.

person febeling    schedule 21.02.2020