Обновите изображения на лету в CloudFront и сразу же получите их одним и тем же URL: AWS CloudFront → S3 → Lambda → CloudFront

TL;DR: Мы должны обмануть кэширование переадресации CloudFront 307, создав новое поведение кэша для ответов, исходящих от нашей функции Lambda.

Вы не поверите, насколько мы должны достичь этого. На последнем шаге мы так сильно застряли.

Бизнес-кейс:

Наше приложение хранит изображения в S3 и обслуживает их с CloudFront, чтобы избежать каких-либо географических замедлений по всему миру. Теперь мы хотим быть очень гибкими с дизайном и иметь возможность запрашивать новые образы изображений непосредственно в URL CouldFront! Каждый новый размер будет создан по требованию, а затем сохранен в S3, поэтому во второй раз он будет запрошен. действительно очень быстро, поскольку он будет существовать в S3, а также будет кэшироваться в CloudFront.

Допустим, пользователь загрузил изображение chucknorris.jpg. Только оригинальное изображение будет сохранено в S3 и будет показано на нашей странице следующим образом:

//xxxxx.cloudfront.net/chucknorris.jpg

Мы вычислили, что теперь нам нужно отобразить миниатюру размером 200x200 пикселей. Поэтому мы помещаем изображение src в наш шаблон:

//xxxxx.cloudfront.net/chucknorris-200x200.jpg

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

Я сделал уродливый рисунок с обзором архитектуры и рабочим процессом о том, как мы это делаем в AWS:

введите описание изображения здесь

Вот как заканчивается Lambda Python:

return {
    'statusCode': '301',
    'headers': {'location': redirect_url},
    'body': ''
}

Проблема:

Если мы переадресуем функцию Lambda на S3, она работает как шарм. Если мы перенаправляемся на CloudFront, он переходит в цикл переадресации, потому что CloudFront кэширует 307 (а также 301, 302 и 303). Как только наша функция Lambda перенаправляется на CloudFront, CloudFront вызывает URL Getaway API вместо того, чтобы получать изображение с S3:

введите описание изображения здесь

Я хотел бы создать новое поведение кэша в вкладке настроек CloudFront Behaviors. Это поведение не должно кэшировать ответы от Lambda или S3 (не знаю, что именно там происходит внутри), но все равно следует кэшировать любые последующие запросы на это изображение с одинаковым размером. Я пытаюсь установить шаблон пути -\d+x\d+\..+$, добавить ARN функции лямбда в добавлении "Ассоциация функций лямбда", и установите тип события Origin Response. Кроме того, я устанавливаю "TTL по умолчанию" на 0.

Но я не могу сохранить поведение из-за некоторой ошибки:

введите описание изображения здесь

Правильно ли мы или идея "Ассоциации Лямбда-функций" совершенно другая?

Ответ 1

Наконец, я смог его решить. Хотя это не действительно структурное решение, оно делает то, что нам нужно.

Во-первых, благодаря ответу Майкла, я использовал шаблоны путей для соответствия всем типам носителей. Во-вторых, страница "Поведение кэш" немного вводила меня в заблуждение: действительно, ассоциация Lambda для Lambda @Edge, хотя я не видел этого нигде во всплывающих подсказках поведения кэша: все, что вы видите, это просто Lambda. Эта функция не может помочь нам, поскольку мы не хотим расширять сферу нашей AWS-службы с помощью Lambda @Edge только из-за этой конкретной проблемы.

Вот подход к решению:
Я определил поведение нескольких кэшей, по одному на тип носителя, который мы поддерживаем:

введите описание изображения здесь

Для каждого поведения кэша я устанавливаю Default TTL как 0.

И самая важная часть: в функции Lambda я добавил заголовок Cache-Control к измененным размерам изображений, когда их помещали в S3:

s3_resource.Bucket(BUCKET).put_object(Key=new_key, 
                                      Body=edited_image_obj,
                                      CacheControl='max-age=12312312',
                                      ContentType=content_type)

Чтобы проверить, что все работает, теперь я вижу, что новое изображение уменьшено с заголовком кэша в CloudFront:

введите описание изображения здесь

Ответ 2

Вы на правильном пути... может быть... но есть как минимум две проблемы.

"Ассоциация ассоциаций лямбда", которую вы настраиваете здесь, называется Lambda @Edge, и она еще не доступна. Единственными пользователями, которые могут получить к нему доступ, являются пользователи, которые подали заявку на участие в ограниченном предварительном просмотре. Ошибка "maximum allowed is 0" означает, что вы не являетесь участником предварительного просмотра. Я не видел никаких объявлений, связанных с тем, когда это будет доступно для всех учетных записей.

Но даже если он доступен, он не поможет вам, здесь, в том, как вы, кажется, ожидаете, потому что я не верю, что триггер Origin Response позволяет вам что-либо сделать, чтобы вызвать CloudFront, чтобы попробовать другой пункт назначения и следуйте за перенаправлением. Если вы видите документацию, которая противоречит этому утверждению, пожалуйста, приложите это к моему вниманию.

Однако... Lambda @Edge будет полезен для установки Cache-Control: no-cache на 307, чтобы CloudFront не кэшировал его, но самому переадресации все равно нужно будет вернуться в браузер.

Обратите внимание, что Lambda @Edge поддерживает только Node, а не Python... так что, возможно, это еще не часть вашего плана. Я не могу сказать, из вопроса.

Читайте о ограниченном просмотре Lambda @Edge.

Вторая проблема:

Я пытаюсь установить шаблон пути -\d+x\d+\..+$

Вы не можете этого сделать. Шаблоны путей - это совпадения строк, поддерживающие подстановочные символы *. Они не являются регулярными выражениями. Вы можете уйти с /*-*x*.jpg, хотя, поскольку несколько подстановочных знаков оказываются поддерживаемыми.