web-dev-qa-db-fra.com

Redimensionnez les images à la volée dans CloudFront et obtenez-les instantanément dans la même URL: AWS CloudFront -> S3 -> Lambda -> CloudFront

TLDR: Nous devons tromper la mise en cache de redirection CloudFront 307 en créant un nouveau comportement de cache pour les réponses provenant de notre fonction Lambda.

Vous ne croirez pas à quel point nous sommes proches pour y parvenir. Nous avons si mal collé dans la dernière étape.

Business case:

Notre application stocke des images dans S3 et les sert avec CloudFront afin d'éviter tout ralentissement géographique à travers le monde. Maintenant, nous voulons être vraiment flexibles avec la conception et pouvoir demander de nouvelles dimensions d'image directement dans l'URL Can'tFront! Chaque nouvelle taille d'image sera créée à la demande, puis stockée dans S3, donc la deuxième fois qu'elle sera demandée, elle sera servie très rapidement car elle existera dans S3 et sera également mise en cache dans CloudFront.

Supposons que l'utilisateur ait téléchargé l'image chucknorris.jpg. Seule l'image originale sera stockée dans S3 et sera servie sur notre page comme ceci:

//xxxxx.cloudfront.net/chucknorris.jpg

Nous avons calculé que nous devons maintenant afficher une miniature de 200x200 pixels. Par conséquent, nous mettons l'image src dans notre modèle:

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

Lorsque cette nouvelle taille est demandée, les services Web Amazon doivent la fournir à la volée dans le même compartiment et avec la clé demandée. De cette façon, l'image sera directement chargée dans la même URL de CloudFront.

J'ai fait un dessin laid avec l'aperçu de l'architecture et le flux de travail sur la façon dont nous faisons cela dans AWS:

enter image description here

Voici comment se termine Python Lambda:

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

Le problème:

Si nous faisons rediriger la fonction Lambda vers S3, cela fonctionne comme un charme. Si nous redirigeons vers CloudFront, il entre dans la boucle de redirection car CloudFront met en cache 307 (ainsi que 301, 302 et 303). Dès que notre fonction Lambda redirige vers CloudFront, CloudFront appelle l'URL Getaway API au lieu de récupérer l'image à partir de S3:

enter image description here

Je voudrais créer un nouveau comportement de cache dans l'onglet Behaviors des paramètres de CloudFront. Ce comportement ne doit pas mettre en cache les réponses de Lambda ou S3 (je ne sais pas exactement ce qui se passe en interne), mais doit toujours mettre en cache toutes les demandes suivies vers cette même image redimensionnée. J'essaie de définir le modèle de chemin -\d+x\d+\..+$, ajoutez l'ARN de la fonction Lambda dans "Lambda Function Association" et définissez le type d'événement Origin Response. À côté de cela, je configure le "TTL par défaut" sur 0.

Mais je ne peux pas enregistrer le comportement en raison d'une erreur:

enter image description here

Sommes-nous sur la bonne voie, ou l'idée de cette "association de fonctions lambda" est-elle totalement différente?

20
katericata

Enfin, j'ai pu le résoudre. Bien que ce ne soit pas vraiment une solution structurelle, elle fait ce dont nous avons besoin.

Tout d'abord, grâce à la réponse de Michael, j'ai utilisé des modèles de chemin pour correspondre à tous les types de médias. Deuxièmement, la page Comportement du cache était un peu trompeuse pour moi: en effet, l'association Lambda est pour Lambda @ Edge, bien que je ne l'ai vu nulle part dans toutes les info-bulles du comportement du cache: tout ce que vous voyez est juste Lambda. Cette fonctionnalité ne peut pas nous aider car nous ne voulons pas étendre notre portée de service AWS avec Lambda @ Edge simplement en raison de ce problème particulier.

Voici l'approche de la solution:
J'ai défini plusieurs comportements de cache, un par type de support que nous prenons en charge:

enter image description here

Pour chaque comportement de cache, j'ai défini le Default TTL être 0.

Et la partie la plus importante: dans la fonction Lambda, j'ai ajouté un Cache-Control en-tête des images redimensionnées lors de leur mise en S3:

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

Pour valider que tout fonctionne, je vois maintenant que la nouvelle dimension d'image est servie avec l'en-tête du cache dans CloudFront:

enter image description here

9
katericata

Vous êtes sur la bonne voie ... peut-être ... mais il y a au moins deux problèmes.

La "Lambda Function Association" que vous configurez ici s'appelle Lambda @ Edge et n'est pas encore disponible. Les seuls utilisateurs qui peuvent y accéder sont les utilisateurs qui ont demandé à être inclus dans l'aperçu limité. Le "maximum allowed is 0" erreur signifie que vous n'êtes pas un participant à l'aperçu. Je n'ai vu aucune annonce concernant la date de mise en ligne de tous les comptes.

Mais même une fois qu'il sera disponible, cela ne vous aidera pas, ici, de la manière que vous attendez, car je ne crois pas qu'un déclencheur Origin Response vous permette de faire quoi que ce soit pour déclencher CloudFront pour essayer une destination différente et suivre le réorienter. Si vous voyez une documentation qui contredit cette affirmation, veuillez la porter à mon attention.

Cependant ... Lambda @ Edge sera utile pour définir Cache-Control: no-cache sur le 307 afin que CloudFront ne le mette pas en cache, mais la redirection elle-même devra toujours remonter jusqu'au navigateur.

Notez également que Lambda @ Edge ne prend en charge que Node, pas Python ... alors peut-être que cela ne fait même pas encore partie de votre plan. Je ne peux pas vraiment dire, à partir de la question.

Lisez l'aperçu limité de Lambda @ Edge .

Le deuxième problème:

J'essaie de définir le modèle de chemin -\d+x\d+\..+$

Tu ne peux pas faire ça. Les modèles de chemin sont des correspondances de chaîne prenant en charge * caractères génériques. Ce ne sont pas des expressions régulières. Vous pourriez vous en sortir avec /*-*x*.jpg, cependant, puisque plusieurs caractères génériques semblent être pris en charge .

1
Michael - sqlbot