web-dev-qa-db-fra.com

AWS API Gateway et Lambda pour renvoyer l'image

Disons que j'ai ce HTML:

<img src="http://example.com/pic"/>

Ce que je voudrais faire, c'est avoir une carte example.com/pic vers un point de terminaison AWS API Gateway.

Ce point de terminaison appelle alors une fonction lambda.

Cette fonction lambda lirait une image aléatoire d'un compartiment s3 et la retournerait.

Mon objectif est donc d'utiliser une balise d'image HTML STANDARD et de me retrouver avec une image d'un compartiment s3 mais en passant par un code de décision dans le lambda pour décider de l'image à renvoyer.

Je sais que vous pouvez utiliser s3 pour servir directement du contenu statique (d'où le lambda pour décider quelle image). Je sais aussi que je pourrais faire des choses dans le lambda comme b64 encoder la réponse et ensuite la gérer sur le client mais je vise à utiliser la balise HTML IMG standard.

Est-ce possible?

J'ai essayé d'utiliser le ResponseStreamHandler (Java SDK) pour le lambda et de renvoyer le tableau d'octets de l'image et j'ai également ajouté la configuration de la passerelle API pour ne pas mapper la sortie sur JSON, mais rien ne semble fonctionner!

14
user1736191

Il semble qu'AWS ait simplifié ce processus, de sorte que de nombreuses réponses sont obsolètes et/ou trop compliquées.

C'est ainsi que j'ai demandé à Lambda de renvoyer une image via l'API Gateway, en juin 2018:

1) Dans API Gateway, activez Use Lambda Proxy integration pour votre API. (Ce paramètre se trouve dans la section Demande d'intégration, où vous aviez défini le type sur Lambda.)

2) Dans API Gateway, sélectionnez votre API et cliquez sur Settings. Dans Binary Media Types ajouter */*. (Remarque: j'ai essayé d'ajouter simplement 'image/jpeg', mais il semble que */* pour que tout cela fonctionne)

3) Assurez-vous de déployer votre API, sinon vos modifications ne seront pas en direct. (Dans API Gateway, sélectionnez votre API, puis Actions> Déployer l'API).

4) Dans votre code Lambda, retournez votre image en encodage Base64 (cet exemple est du code C #):

    // set the Content-type header
    // set to whichever image type you're returning
    var headersDic = new Dictionary<string, string>();
    headersDic.Add("Content-type", "image/jpeg");

    // return the response object that APIGateway requires
    return new APIGatewayProxyResponse
    {
        StatusCode = 200,
        Headers = headersDic,
        // return the image in Base64 encoding
        Body = Convert.ToBase64String(...your image data...),
        IsBase64Encoded = true
    };

Terminé.

Si vous avez configuré votre API pour ne pas exiger d'authentification, tapez simplement votre lien API dans votre navigateur et il affichera l'image. Ou placez le lien API dans une balise IMG. par exemple. <img src="https://asdf.execute-api.us-east-1.amazonaws.com/live/myapi" />

Remarque: même si à l'étape 2, vous définissez le Binary Media Types à */*, API Gateway renverra toujours du texte si c'est ce que renvoie votre Lambda.

22
Doug S

Heureusement, AWS API Gateway prend désormais en charge les données binaires, mais vous devez également mettre à jour votre méthode de ressource via la CLI car elle n'est pas encore implémentée dans la console. Voici ce que vous devez faire:

  1. Dans la réponse de la méthode de votre méthode
    Ensemble Content-Type comme image/jpeg dans l'en-tête de réponse d'état HTTP 200
  2. Dans la réponse d'intégration de votre méthode
    Ensemble Content-Type comme 'image/jpeg' dans les mappages d'en-tête. Attention aux citations!
  3. Avec l'AWS CLI, définissez l'attribut contentHandling sur CONVERT_TO_BINARYsur votre réponse d'intégration

Vérifiez l'ensemble du processus dans ce grand guide étape par étape: https://stackoverflow.com/a/41434295/720665

7
David Salamon

J'ai rencontré un problème similaire. Comme mentionné, vous ne pouvez pas actuellement renvoyer directement votre image au format binaire à partir de votre point de terminaison API Gateway, ce qui serait nécessaire pour que le navigateur l'affiche correctement.

Cependant, j'ai résolu ce problème en demandant à la passerelle API de renvoyer un 2 Redirect, pointant vers le fichier correct dans S3. Vous pouvez demander à votre fonction Lambda de renvoyer l'URL au fichier, qui est ensuite mappé à l'en-tête Location dans API Gateway. Le navigateur suivra la redirection et affichera correctement l'image.

Il existe plusieurs façons d'implémenter la redirection, mais j'ai fait comme suit:

  • Lambda renvoie un objet avec l'image cible comme suit:

    function handler(event, context) {
         context.succeed({ 
             location: "https://[bucket-name].s3-eu-west-1.amazonaws.com/myimage.png" });
         });
    }
    
  • Supprimez l'état de réponse de méthode "200" normal de la réponse d'intégration dans API Gateway. Remplacez-le par un état de réponse "302" et ajoutez l'en-tête "Location" mappé à la valeur "integration.response.body.location"

  • Ajoutez également le statut 302 à la réponse de méthode

5
Theodor

Juste pour être clair, le client fait deux demandes différentes:

  1. Le premier à obtenir le code HTML (y compris l'url de l'image).
  2. Le second pour récupérer les données d'image de l'url.

En d'autres termes, les données d'image ne sont pas intégrées dans le HTML.

Sur la base de ces connaissances, vous pouvez avoir une Lambda (derrière la passerelle API) comme vous le suggérez. L'implémentation Lambda peut avoir une logique qui détermine l'URL de l'image stockée dans S3. Cependant, la Lambda renvoie des données JSON et non HTML (il existe des solutions de contournement telles que renvoyer le code HTML dans une variable ), ce qui rend les choses plus délicates, en particulier pour les grandes pages HTML.

Je suggère une approche légèrement différente, car la simple réception d'une balise d'image ne vous mènera pas loin. Je suppose que vous insérerez la balise image dans un document HTML, probablement en utilisant JavaScript. Vous pouvez également laisser la demande API Gateway/Lambda renvoyer un document JSON avec l'URL d'image et laisser le JavaScript mettre à jour une balise d'image existante avec la nouvelle URL ou générer la balise pour vous.

1
matsev

Ce n'est actuellement pas possible car vous ne pouvez pas renvoyer de données binaires via AWS API Gateway.

Pour que cela fonctionne, la fonction lambda devrait renvoyer les données d'image sous forme d'objet binaire et certaines méta-informations telles que le type de contenu d'image. Ensuite, AWS API Gateway devrait pouvoir mapper cela à la réponse HTTP. Par exemple:-

lambda renvoie: { contentType: 'image/png', image: "encoded binary data" }

la passerelle API devrait alors mapper contentType à l'en-tête "content-type" de la réponse, et placer les données d'image dans le corps de la réponse avec le bon encodage et la bonne longueur.

Malheureusement, il ne le fait pas pour le moment. Il mappe uniquement les encodages de texte comme application/json ou application/xml comme type de réponse (il est finalement conçu pour les API).

Vous pouvez très facilement y parvenir en utilisant ElasticBeanstalk où vous avez beaucoup plus de contrôle sur la réponse http.

0
aomega