Exemples de fonctions Lambda@Edge - Amazon CloudFront

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Exemples de fonctions Lambda@Edge

Consultez les sections suivantes pour des exemples d'utilisation des fonctions Lambda avec Amazon. CloudFront

Note

Si vous choisissez d'exécuter Node.js 18 ou une version ultérieure pour votre fonction Lambda @Edge, un index.mjs fichier est créé automatiquement pour vous. Pour utiliser les exemples de code suivants, renommez index.js plutôt le index.mjs fichier en.

Exemples généraux

Les exemples présentés dans cette section illustrent certaines manières courantes d'utiliser Lambda @Edge dans. CloudFront

Exemple : test A/B

Vous pouvez utiliser l'exemple suivant pour tester deux versions différentes d'une image sans créer de redirections ni modifier l'URL. Cet exemple lit les cookies dans la demande de l'utilisateur et modifie l'URL de la demande en conséquence. Si l'utilisateur n'envoie pas de cookie avec l'une des valeurs attendues, l'exemple affecte de façon aléatoire l'utilisateur à l'une des URL.

Node.js
'use strict'; exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const headers = request.headers; if (request.uri !== '/experiment-pixel.jpg') { // do not process if this is not an A-B test request callback(null, request); return; } const cookieExperimentA = 'X-Experiment-Name=A'; const cookieExperimentB = 'X-Experiment-Name=B'; const pathExperimentA = '/experiment-group/control-pixel.jpg'; const pathExperimentB = '/experiment-group/treatment-pixel.jpg'; /* * Lambda at the Edge headers are array objects. * * Client may send multiple Cookie headers, i.e.: * > GET /viewerRes/test HTTP/1.1 * > User-Agent: curl/7.18.1 (x86_64-unknown-linux-gnu) libcurl/7.18.1 OpenSSL/1.0.1u zlib/1.2.3 * > Cookie: First=1; Second=2 * > Cookie: ClientCode=abc * > Host: example.com * * You can access the first Cookie header at headers["cookie"][0].value * and the second at headers["cookie"][1].value. * * Header values are not parsed. In the example above, * headers["cookie"][0].value is equal to "First=1; Second=2" */ let experimentUri; if (headers.cookie) { for (let i = 0; i < headers.cookie.length; i++) { if (headers.cookie[i].value.indexOf(cookieExperimentA) >= 0) { console.log('Experiment A cookie found'); experimentUri = pathExperimentA; break; } else if (headers.cookie[i].value.indexOf(cookieExperimentB) >= 0) { console.log('Experiment B cookie found'); experimentUri = pathExperimentB; break; } } } if (!experimentUri) { console.log('Experiment cookie has not been found. Throwing dice...'); if (Math.random() < 0.75) { experimentUri = pathExperimentA; } else { experimentUri = pathExperimentB; } } request.uri = experimentUri; console.log(`Request uri set to "${request.uri}"`); callback(null, request); };
Python
import json import random def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] headers = request['headers'] if request['uri'] != '/experiment-pixel.jpg': # Not an A/B Test return request cookieExperimentA, cookieExperimentB = 'X-Experiment-Name=A', 'X-Experiment-Name=B' pathExperimentA, pathExperimentB = '/experiment-group/control-pixel.jpg', '/experiment-group/treatment-pixel.jpg' ''' Lambda at the Edge headers are array objects. Client may send multiple cookie headers. For example: > GET /viewerRes/test HTTP/1.1 > User-Agent: curl/7.18.1 (x86_64-unknown-linux-gnu) libcurl/7.18.1 OpenSSL/1.0.1u zlib/1.2.3 > Cookie: First=1; Second=2 > Cookie: ClientCode=abc > Host: example.com You can access the first Cookie header at headers["cookie"][0].value and the second at headers["cookie"][1].value. Header values are not parsed. In the example above, headers["cookie"][0].value is equal to "First=1; Second=2" ''' experimentUri = "" for cookie in headers.get('cookie', []): if cookieExperimentA in cookie['value']: print("Experiment A cookie found") experimentUri = pathExperimentA break elif cookieExperimentB in cookie['value']: print("Experiment B cookie found") experimentUri = pathExperimentB break if not experimentUri: print("Experiment cookie has not been found. Throwing dice...") if random.random() < 0.75: experimentUri = pathExperimentA else: experimentUri = pathExperimentB request['uri'] = experimentUri print(f"Request uri set to {experimentUri}") return request

Exemple : remplacer un en-tête de réponse

L'exemple suivant montre comment changer la valeur d'un en-tête de réponse en fonction de la valeur d'un autre en-tête.

Node.js
'use strict'; exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; const headerNameSrc = 'X-Amz-Meta-Last-Modified'; const headerNameDst = 'Last-Modified'; if (headers[headerNameSrc.toLowerCase()]) { headers[headerNameDst.toLowerCase()] = [ headers[headerNameSrc.toLowerCase()][0], ]; console.log(`Response header "${headerNameDst}" was set to ` + `"${headers[headerNameDst.toLowerCase()][0].value}"`); } callback(null, response); };
Python
import json def lambda_handler(event, context): response = event["Records"][0]["cf"]["response"] headers = response["headers"] headerNameSrc = "X-Amz-Meta-Last-Modified" headerNameDst = "Last-Modified" if headers.get(headerNameSrc.lower(), None): headers[headerNameDst.lower()] = [headers[headerNameSrc.lower()][0]] print(f"Response header {headerNameDst.lower()} was set to {headers[headerNameSrc.lower()][0]}") return response

Générer des réponses - exemples

Les exemples de cette section illustrent l'utilisation de Lambda@Edge pour générer des réponses.

Exemple : diffuser du contenu statique (réponse générée)

L'exemple suivant montre comment utiliser une fonction Lambda pour traiter le contenu statique d'un site web, ce qui réduit la charge sur le serveur d'origine et réduit la latence globale.

Note

Vous pouvez générer des réponses HTTP pour les événements de requête utilisateur ou de requête à l'origine. Pour plus d’informations, consultez Générer des réponses HTTP dans les déclencheurs de requêtes.

Vous pouvez également remplacer ou supprimer le corps de la réponse HTTP dans les événements de réponse de l’origine. Pour plus d’informations, consultez Mettre à jour les réponses HTTP dans les déclencheurs de réponse d'origine.

Node.js
'use strict'; const content = ` <\!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Simple Lambda@Edge Static Content Response</title> </head> <body> <p>Hello from Lambda@Edge!</p> </body> </html> `; exports.handler = (event, context, callback) => { /* * Generate HTTP OK response using 200 status code with HTML body. */ const response = { status: '200', statusDescription: 'OK', headers: { 'cache-control': [{ key: 'Cache-Control', value: 'max-age=100' }], 'content-type': [{ key: 'Content-Type', value: 'text/html' }] }, body: content, }; callback(null, response); };
Python
import json CONTENT = """ <\!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Simple Lambda@Edge Static Content Response</title> </head> <body> <p>Hello from Lambda@Edge!</p> </body> </html> """ def lambda_handler(event, context): # Generate HTTP OK response using 200 status code with HTML body. response = { 'status': '200', 'statusDescription': 'OK', 'headers': { 'cache-control': [ { 'key': 'Cache-Control', 'value': 'max-age=100' } ], "content-type": [ { 'key': 'Content-Type', 'value': 'text/html' } ] }, 'body': CONTENT } return response

Exemple : générer une redirection HTTP (réponse générée)

L'exemple suivant montre comment générer une redirection HTTP.

Note

Vous pouvez générer des réponses HTTP pour les événements de requête utilisateur ou de requête à l'origine. Pour plus d’informations, consultez Générer des réponses HTTP dans les déclencheurs de requêtes.

Node.js
'use strict'; exports.handler = (event, context, callback) => { /* * Generate HTTP redirect response with 302 status code and Location header. */ const response = { status: '302', statusDescription: 'Found', headers: { location: [{ key: 'Location', value: 'https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html', }], }, }; callback(null, response); };
Python
def lambda_handler(event, context): # Generate HTTP redirect response with 302 status code and Location header. response = { 'status': '302', 'statusDescription': 'Found', 'headers': { 'location': [{ 'key': 'Location', 'value': 'https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html' }] } } return response

Chaînes de requête - exemples

Les exemples de cette section illustrent plusieurs méthodes d'utilisation de Lambda@Edge avec des chaînes de requête.

Exemple : ajout d'un en-tête basé sur un paramètre de chaîne de requête

L'exemple suivant montre comment obtenir la paire clé-valeur d'un paramètre de chaîne de requête, puis ajouter un en-tête en fonction de ces valeurs.

Node.js
'use strict'; const querystring = require('querystring'); exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; /* When a request contains a query string key-value pair but the origin server * expects the value in a header, you can use this Lambda function to * convert the key-value pair to a header. Here's what the function does: * 1. Parses the query string and gets the key-value pair. * 2. Adds a header to the request using the key-value pair that the function got in step 1. */ /* Parse request querystring to get javascript object */ const params = querystring.parse(request.querystring); /* Move auth param from querystring to headers */ const headerName = 'Auth-Header'; request.headers[headerName.toLowerCase()] = [{ key: headerName, value: params.auth }]; delete params.auth; /* Update request querystring */ request.querystring = querystring.stringify(params); callback(null, request); };
Python
from urllib.parse import parse_qs, urlencode def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] ''' When a request contains a query string key-value pair but the origin server expects the value in a header, you can use this Lambda function to convert the key-value pair to a header. Here's what the function does: 1. Parses the query string and gets the key-value pair. 2. Adds a header to the request using the key-value pair that the function got in step 1. ''' # Parse request querystring to get dictionary/json params = {k : v[0] for k, v in parse_qs(request['querystring']).items()} # Move auth param from querystring to headers headerName = 'Auth-Header' request['headers'][headerName.lower()] = [{'key': headerName, 'value': params['auth']}] del params['auth'] # Update request querystring request['querystring'] = urlencode(params) return request

Exemple : normalisation des paramètres de chaîne de requête pour améliorer le taux de réussite du cache

L'exemple suivant montre comment améliorer le taux de réussite de votre cache en apportant les modifications suivantes aux chaînes de requête avant de CloudFront transférer les demandes à votre origine :

  • Classez par ordre alphabétique les paires clé-valeur selon le nom du paramètre.

  • Modifiez la casse des paires clé-valeur en minuscules.

Pour plus d’informations, consultez Contenu du cache basé sur les paramètres de chaîne de requête.

Node.js
'use strict'; const querystring = require('querystring'); exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; /* When you configure a distribution to forward query strings to the origin and * to cache based on an allowlist of query string parameters, we recommend * the following to improve the cache-hit ratio: * - Always list parameters in the same order. * - Use the same case for parameter names and values. * * This function normalizes query strings so that parameter names and values * are lowercase and parameter names are in alphabetical order. * * For more information, see: * https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html */ console.log('Query String: ', request.querystring); /* Parse request query string to get javascript object */ const params = querystring.parse(request.querystring.toLowerCase()); const sortedParams = {}; /* Sort param keys */ Object.keys(params).sort().forEach(key => { sortedParams[key] = params[key]; }); /* Update request querystring with normalized */ request.querystring = querystring.stringify(sortedParams); callback(null, request); };
Python
from urllib.parse import parse_qs, urlencode def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] ''' When you configure a distribution to forward query strings to the origin and to cache based on an allowlist of query string parameters, we recommend the following to improve the cache-hit ratio: Always list parameters in the same order. - Use the same case for parameter names and values. This function normalizes query strings so that parameter names and values are lowercase and parameter names are in alphabetical order. For more information, see: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html ''' print("Query string: ", request["querystring"]) # Parse request query string to get js object params = {k : v[0] for k, v in parse_qs(request['querystring'].lower()).items()} # Sort param keys sortedParams = sorted(params.items(), key=lambda x: x[0]) # Update request querystring with normalized request['querystring'] = urlencode(sortedParams) return request

Exemple : rediriger les utilisateurs non authentifiés vers une page de connexion

L'exemple suivant montre comment rediriger des utilisateurs vers une page de connexion s'ils n'ont pas saisi leurs informations d'identification.

Node.js
'use strict'; function parseCookies(headers) { const parsedCookie = {}; if (headers.cookie) { headers.cookie[0].value.split(';').forEach((cookie) => { if (cookie) { const parts = cookie.split('='); parsedCookie[parts[0].trim()] = parts[1].trim(); } }); } return parsedCookie; } exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const headers = request.headers; /* Check for session-id in request cookie in viewer-request event, * if session-id is absent, redirect the user to sign in page with original * request sent as redirect_url in query params. */ /* Check for session-id in cookie, if present then proceed with request */ const parsedCookies = parseCookies(headers); if (parsedCookies && parsedCookies['session-id']) { callback(null, request); return; } /* URI encode the original request to be sent as redirect_url in query params */ const encodedRedirectUrl = encodeURIComponent(`https://${headers.host[0].value}${request.uri}?${request.querystring}`); const response = { status: '302', statusDescription: 'Found', headers: { location: [{ key: 'Location', value: `https://www.example.com/signin?redirect_url=${encodedRedirectUrl}`, }], }, }; callback(null, response); };
Python
import urllib def parseCookies(headers): parsedCookie = {} if headers.get('cookie'): for cookie in headers['cookie'][0]['value'].split(';'): if cookie: parts = cookie.split('=') parsedCookie[parts[0].strip()] = parts[1].strip() return parsedCookie def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] headers = request['headers'] ''' Check for session-id in request cookie in viewer-request event, if session-id is absent, redirect the user to sign in page with original request sent as redirect_url in query params. ''' # Check for session-id in cookie, if present, then proceed with request parsedCookies = parseCookies(headers) if parsedCookies and parsedCookies['session-id']: return request # URI encode the original request to be sent as redirect_url in query params redirectUrl = "https://%s%s?%s" % (headers['host'][0]['value'], request['uri'], request['querystring']) encodedRedirectUrl = urllib.parse.quote_plus(redirectUrl.encode('utf-8')) response = { 'status': '302', 'statusDescription': 'Found', 'headers': { 'location': [{ 'key': 'Location', 'value': 'https://www.example.com/signin?redirect_url=%s' % encodedRedirectUrl }] } } return response

Personnalisation de contenu à l'aide des en-têtes Pays ou Type d'appareil – exemples

Les exemples de cette section illustrent une méthode d'utilisation de Lambda@Edge pour personnaliser le comportement en fonction de l'emplacement ou du type d'appareil utilisé par l'utilisateur.

Exemple : rediriger les demandes des visiteurs vers une URL spécifique à un pays

L'exemple suivant montre comment générer une réponse de redirection HTTP avec une URL propre à un pays et renvoyer la réponse à l'utilisateur. Ceci s'avère utile lorsque vous souhaitez fournir des réponses propres à un pays. Exemples :

  • Si vous avez des sous-domaines propres à un pays, comme us.example.com et tw.example.com, vous pouvez générer une réponse de redirection lorsqu'un utilisateur demande example.com.

  • Si vous diffusez une vidéo, mais que vous ne disposez pas de droits pour diffuser le contenu dans un pays spécifique, vous pouvez rediriger les utilisateurs de ce pays vers une page qui explique pourquoi ils ne peuvent regarder la vidéo.

Remarques :

  • Vous devez configurer votre distribution pour être mise en cache en fonction de l'en-tête CloudFront-Viewer-Country. Pour plus d’informations, consultez Mise en cache basée sur des en-têtes de demande sélectionnés.

  • CloudFront ajoute l'CloudFront-Viewer-Countryen-tête après l'événement de demande du spectateur. Pour utiliser cet exemple, vous devez créer un déclencheur pour l'événement de demande à l'origine.

Node.js
'use strict'; /* This is an origin request function */ exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const headers = request.headers; /* * Based on the value of the CloudFront-Viewer-Country header, generate an * HTTP status code 302 (Redirect) response, and return a country-specific * URL in the Location header. * NOTE: 1. You must configure your distribution to cache based on the * CloudFront-Viewer-Country header. For more information, see * https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers * 2. CloudFront adds the CloudFront-Viewer-Country header after the viewer * request event. To use this example, you must create a trigger for the * origin request event. */ let url = 'https://example.com/'; if (headers['cloudfront-viewer-country']) { const countryCode = headers['cloudfront-viewer-country'][0].value; if (countryCode === 'TW') { url = 'https://tw.example.com/'; } else if (countryCode === 'US') { url = 'https://us.example.com/'; } } const response = { status: '302', statusDescription: 'Found', headers: { location: [{ key: 'Location', value: url, }], }, }; callback(null, response); };
Python
# This is an origin request function def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] headers = request['headers'] ''' Based on the value of the CloudFront-Viewer-Country header, generate an HTTP status code 302 (Redirect) response, and return a country-specific URL in the Location header. NOTE: 1. You must configure your distribution to cache based on the CloudFront-Viewer-Country header. For more information, see https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers 2. CloudFront adds the CloudFront-Viewer-Country header after the viewer request event. To use this example, you must create a trigger for the origin request event. ''' url = 'https://example.com/' viewerCountry = headers.get('cloudfront-viewer-country') if viewerCountry: countryCode = viewerCountry[0]['value'] if countryCode == 'TW': url = 'https://tw.example.com/' elif countryCode == 'US': url = 'https://us.example.com/' response = { 'status': '302', 'statusDescription': 'Found', 'headers': { 'location': [{ 'key': 'Location', 'value': url }] } } return response

Exemple : servir différentes versions d'un objet en fonction de l'appareil

L'exemple suivant montre comment servir différentes versions d'un objet en fonction du type d'appareil employé par l'utilisateur, par exemple, un appareil mobile ou une tablette. Remarques :

  • Vous devez configurer votre distribution pour être mise en cache en fonction des en-têtes CloudFront-Is-*-Viewer. Pour plus d’informations, consultez Mise en cache basée sur des en-têtes de demande sélectionnés.

  • CloudFront ajoute les CloudFront-Is-*-Viewer en-têtes après l'événement de demande du spectateur. Pour utiliser cet exemple, vous devez créer un déclencheur pour l'événement de demande à l'origine.

Node.js
'use strict'; /* This is an origin request function */ exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const headers = request.headers; /* * Serve different versions of an object based on the device type. * NOTE: 1. You must configure your distribution to cache based on the * CloudFront-Is-*-Viewer headers. For more information, see * the following documentation: * https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers * https://docs.aws.amazon.com/console/cloudfront/cache-on-device-type * 2. CloudFront adds the CloudFront-Is-*-Viewer headers after the viewer * request event. To use this example, you must create a trigger for the * origin request event. */ const desktopPath = '/desktop'; const mobilePath = '/mobile'; const tabletPath = '/tablet'; const smarttvPath = '/smarttv'; if (headers['cloudfront-is-desktop-viewer'] && headers['cloudfront-is-desktop-viewer'][0].value === 'true') { request.uri = desktopPath + request.uri; } else if (headers['cloudfront-is-mobile-viewer'] && headers['cloudfront-is-mobile-viewer'][0].value === 'true') { request.uri = mobilePath + request.uri; } else if (headers['cloudfront-is-tablet-viewer'] && headers['cloudfront-is-tablet-viewer'][0].value === 'true') { request.uri = tabletPath + request.uri; } else if (headers['cloudfront-is-smarttv-viewer'] && headers['cloudfront-is-smarttv-viewer'][0].value === 'true') { request.uri = smarttvPath + request.uri; } console.log(`Request uri set to "${request.uri}"`); callback(null, request); };
Python
# This is an origin request function def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] headers = request['headers'] ''' Serve different versions of an object based on the device type. NOTE: 1. You must configure your distribution to cache based on the CloudFront-Is-*-Viewer headers. For more information, see the following documentation: https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers https://docs.aws.amazon.com/console/cloudfront/cache-on-device-type 2. CloudFront adds the CloudFront-Is-*-Viewer headers after the viewer request event. To use this example, you must create a trigger for the origin request event. ''' desktopPath = '/desktop'; mobilePath = '/mobile'; tabletPath = '/tablet'; smarttvPath = '/smarttv'; if 'cloudfront-is-desktop-viewer' in headers and headers['cloudfront-is-desktop-viewer'][0]['value'] == 'true': request['uri'] = desktopPath + request['uri'] elif 'cloudfront-is-mobile-viewer' in headers and headers['cloudfront-is-mobile-viewer'][0]['value'] == 'true': request['uri'] = mobilePath + request['uri'] elif 'cloudfront-is-tablet-viewer' in headers and headers['cloudfront-is-tablet-viewer'][0]['value'] == 'true': request['uri'] = tabletPath + request['uri'] elif 'cloudfront-is-smarttv-viewer' in headers and headers['cloudfront-is-smarttv-viewer'][0]['value'] == 'true': request['uri'] = smarttvPath + request['uri'] print("Request uri set to %s" % request['uri']) return request

Sélection d'origine dynamique basée sur le contenu – exemples

Les exemples de cette section illustrent une méthode d'utilisation de Lambda@Edge pour acheminer vers différentes origines en fonction des informations contenues dans la demande.

Exemple : utiliser un déclencheur de demande d'origine pour passer d'une origine personnalisée à une origine Amazon S3

Cette fonction explique comment un déclencheur de demande à l'origine peut être utilisé pour passer d'une origine personnalisée à une origine Amazon S3 à partir de laquelle le contenu est récupéré en fonction des propriétés de la demande.

Node.js
'use strict'; const querystring = require('querystring'); exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; /** * Reads query string to check if S3 origin should be used, and * if true, sets S3 origin properties. */ const params = querystring.parse(request.querystring); if (params['useS3Origin']) { if (params['useS3Origin'] === 'true') { const s3DomainName = 'my-bucket.s3.amazonaws.com'; /* Set S3 origin fields */ request.origin = { s3: { domainName: s3DomainName, region: '', authMethod: 'none', path: '', customHeaders: {} } }; request.headers['host'] = [{ key: 'host', value: s3DomainName}]; } } callback(null, request); };
Python
from urllib.parse import parse_qs def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] ''' Reads query string to check if S3 origin should be used, and if true, sets S3 origin properties ''' params = {k: v[0] for k, v in parse_qs(request['querystring']).items()} if params.get('useS3Origin') == 'true': s3DomainName = 'my-bucket.s3.amazonaws.com' # Set S3 origin fields request['origin'] = { 's3': { 'domainName': s3DomainName, 'region': '', 'authMethod': 'none', 'path': '', 'customHeaders': {} } } request['headers']['host'] = [{'key': 'host', 'value': s3DomainName}] return request

Exemple : utiliser un déclencheur de demande d'origine pour modifier la région d'origine d'Amazon S3

Cette fonction explique comment un déclencheur de demande à l'origine peut être utilisé pour modifier l'origine Amazon S3 à partir de laquelle le contenu est récupéré en fonction des propriétés de la demande.

Dans cet exemple, nous utilisons la valeur de l'en-tête CloudFront-Viewer-Country pour mettre à jour le nom de domaine de compartiment S3 en spécifiant un compartiment dans une région plus proche de l'utilisateur. Cela peut être utile à plusieurs égards :

  • Cela réduit la latence lorsque la région spécifiée est plus proche du pays de l'utilisateur.

  • Il est possible de contrôler les données en s'assurant qu'elles sont distribuées depuis une origine qui se trouve dans le pays de provenance de la demande.

Pour utiliser cet exemple, vous devez procéder comme suit :

  • Vous devez configurer votre distribution à mettre en cache en fonction de l'en-tête CloudFront-Viewer-Country. Pour plus d’informations, consultez Mise en cache basée sur des en-têtes de demande sélectionnés.

  • Créez un déclencheur pour cette fonction dans l'événement de demande d'origine. CloudFrontajoute l'CloudFront-Viewer-Countryen-tête après l'événement de demande du visualiseur. Pour utiliser cet exemple, vous devez vous assurer que la fonction s'exécute pour une demande d'origine.

Node.js
'use strict'; exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; /** * This blueprint demonstrates how an origin-request trigger can be used to * change the origin from which the content is fetched, based on request properties. * In this example, we use the value of the CloudFront-Viewer-Country header * to update the S3 bucket domain name to a bucket in a Region that is closer to * the viewer. * * This can be useful in several ways: * 1) Reduces latencies when the Region specified is nearer to the viewer's * country. * 2) Provides data sovereignty by making sure that data is served from an * origin that's in the same country that the request came from. * * NOTE: 1. You must configure your distribution to cache based on the * CloudFront-Viewer-Country header. For more information, see * https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers * 2. CloudFront adds the CloudFront-Viewer-Country header after the viewer * request event. To use this example, you must create a trigger for the * origin request event. */ const countryToRegion = { 'DE': 'eu-central-1', 'IE': 'eu-west-1', 'GB': 'eu-west-2', 'FR': 'eu-west-3', 'JP': 'ap-northeast-1', 'IN': 'ap-south-1' }; if (request.headers['cloudfront-viewer-country']) { const countryCode = request.headers['cloudfront-viewer-country'][0].value; const region = countryToRegion[countryCode]; /** * If the viewer's country is not in the list you specify, the request * goes to the default S3 bucket you've configured. */ if (region) { /** * If you've set up OAI, the bucket policy in the destination bucket * should allow the OAI GetObject operation, as configured by default * for an S3 origin with OAI. Another requirement with OAI is to provide * the Region so it can be used for the SIGV4 signature. Otherwise, the * Region is not required. */ request.origin.s3.region = region; const domainName = `my-bucket-in-${region}.s3.amazonaws.com`; request.origin.s3.domainName = domainName; request.headers['host'] = [{ key: 'host', value: domainName }]; } } callback(null, request); };
Python
def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] ''' This blueprint demonstrates how an origin-request trigger can be used to change the origin from which the content is fetched, based on request properties. In this example, we use the value of the CloudFront-Viewer-Country header to update the S3 bucket domain name to a bucket in a Region that is closer to the viewer. This can be useful in several ways: 1) Reduces latencies when the Region specified is nearer to the viewer's country. 2) Provides data sovereignty by making sure that data is served from an origin that's in the same country that the request came from. NOTE: 1. You must configure your distribution to cache based on the CloudFront-Viewer-Country header. For more information, see https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers 2. CloudFront adds the CloudFront-Viewer-Country header after the viewer request event. To use this example, you must create a trigger for the origin request event. ''' countryToRegion = { 'DE': 'eu-central-1', 'IE': 'eu-west-1', 'GB': 'eu-west-2', 'FR': 'eu-west-3', 'JP': 'ap-northeast-1', 'IN': 'ap-south-1' } viewerCountry = request['headers'].get('cloudfront-viewer-country') if viewerCountry: countryCode = viewerCountry[0]['value'] region = countryToRegion.get(countryCode) # If the viewer's country in not in the list you specify, the request # goes to the default S3 bucket you've configured if region: ''' If you've set up OAI, the bucket policy in the destination bucket should allow the OAI GetObject operation, as configured by default for an S3 origin with OAI. Another requirement with OAI is to provide the Region so it can be used for the SIGV4 signature. Otherwise, the Region is not required. ''' request['origin']['s3']['region'] = region domainName = 'my-bucket-in-%s.s3.amazonaws.com' % region request['origin']['s3']['domainName'] = domainName request['headers']['host'] = [{'key': 'host', 'value': domainName}] return request

Exemple : utiliser un déclencheur de demande d'origine pour passer d'une origine Amazon S3 à une origine personnalisée

Cette fonction explique comment un déclencheur de demande à l'origine peut être utilisé pour modifier l'origine personnalisée à partir de laquelle le contenu est récupéré, en fonction des propriétés de la demande.

Node.js
'use strict'; const querystring = require('querystring'); exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; /** * Reads query string to check if custom origin should be used, and * if true, sets custom origin properties. */ const params = querystring.parse(request.querystring); if (params['useCustomOrigin']) { if (params['useCustomOrigin'] === 'true') { /* Set custom origin fields*/ request.origin = { custom: { domainName: 'www.example.com', port: 443, protocol: 'https', path: '', sslProtocols: ['TLSv1', 'TLSv1.1'], readTimeout: 5, keepaliveTimeout: 5, customHeaders: {} } }; request.headers['host'] = [{ key: 'host', value: 'www.example.com'}]; } } callback(null, request); };
Python
from urllib.parse import parse_qs def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] # Reads query string to check if custom origin should be used, and # if true, sets custom origin properties params = {k: v[0] for k, v in parse_qs(request['querystring']).items()} if params.get('useCustomOrigin') == 'true': # Set custom origin fields request['origin'] = { 'custom': { 'domainName': 'www.example.com', 'port': 443, 'protocol': 'https', 'path': '', 'sslProtocols': ['TLSv1', 'TLSv1.1'], 'readTimeout': 5, 'keepaliveTimeout': 5, 'customHeaders': {} } } request['headers']['host'] = [{'key': 'host', 'value': 'www.example.com'}] return request

Exemple : utilisez un déclencheur de demande d'origine pour transférer progressivement le trafic d'un compartiment Amazon S3 à un autre

Cette fonction montre comment transférer progressivement le trafic d'un compartiment Amazon S3 à un autre de manière contrôlée.

Node.js
'use strict'; function getRandomInt(min, max) { /* Random number is inclusive of min and max*/ return Math.floor(Math.random() * (max - min + 1)) + min; } exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const BLUE_TRAFFIC_PERCENTAGE = 80; /** * This Lambda function demonstrates how to gradually transfer traffic from * one S3 bucket to another in a controlled way. * We define a variable BLUE_TRAFFIC_PERCENTAGE which can take values from * 1 to 100. If the generated randomNumber less than or equal to BLUE_TRAFFIC_PERCENTAGE, traffic * is re-directed to blue-bucket. If not, the default bucket that we've configured * is used. */ const randomNumber = getRandomInt(1, 100); if (randomNumber <= BLUE_TRAFFIC_PERCENTAGE) { const domainName = 'blue-bucket.s3.amazonaws.com'; request.origin.s3.domainName = domainName; request.headers['host'] = [{ key: 'host', value: domainName}]; } callback(null, request); };
Python
import math import random def getRandomInt(min, max): # Random number is inclusive of min and max return math.floor(random.random() * (max - min + 1)) + min def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] BLUE_TRAFFIC_PERCENTAGE = 80 ''' This Lambda function demonstrates how to gradually transfer traffic from one S3 bucket to another in a controlled way. We define a variable BLUE_TRAFFIC_PERCENTAGE which can take values from 1 to 100. If the generated randomNumber less than or equal to BLUE_TRAFFIC_PERCENTAGE, traffic is re-directed to blue-bucket. If not, the default bucket that we've configured is used. ''' randomNumber = getRandomInt(1, 100) if randomNumber <= BLUE_TRAFFIC_PERCENTAGE: domainName = 'blue-bucket.s3.amazonaws.com' request['origin']['s3']['domainName'] = domainName request['headers']['host'] = [{'key': 'host', 'value': domainName}] return request

Exemple : utilisez un déclencheur de demande d'origine pour modifier le nom de domaine d'origine en fonction de l'en-tête du pays

Cette fonction explique comment vous pouvez modifier le nom de domaine de l'origine en fonction de l'en-tête CloudFront-Viewer-Country afin que le contenu soit transmis depuis une origine plus proche du pays de l'utilisateur.

La mise en œuvre de cette fonctionnalité pour votre distribution peut avoir les avantages suivants :

  • Réduction de la latence lorsque la région spécifiée est plus proche du pays de l'utilisateur

  • Assurance de la souveraineté des données en veillant à ce que les données soient distribuées depuis une origine qui se trouve dans le pays d'où vient la demande

Notez que pour activer cette fonctionnalité, vous devez configurer votre distribution pour qu'elle soit mise en cache en fonction de l'en-tête CloudFront-Viewer-Country. Pour plus d’informations, consultez Mise en cache basée sur des en-têtes de demande sélectionnés.

Node.js
'use strict'; exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; if (request.headers['cloudfront-viewer-country']) { const countryCode = request.headers['cloudfront-viewer-country'][0].value; if (countryCode === 'GB' || countryCode === 'DE' || countryCode === 'IE' ) { const domainName = 'eu.example.com'; request.origin.custom.domainName = domainName; request.headers['host'] = [{key: 'host', value: domainName}]; } } callback(null, request); };
Python
def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] viewerCountry = request['headers'].get('cloudfront-viewer-country') if viewerCountry: countryCode = viewerCountry[0]['value'] if countryCode == 'GB' or countryCode == 'DE' or countryCode == 'IE': domainName = 'eu.example.com' request['origin']['custom']['domainName'] = domainName request['headers']['host'] = [{'key': 'host', 'value': domainName}] return request

Mettre à jour les statuts d'erreur - exemples

Les exemples de cette section fournissent des conseils sur l'utilisation de Lambda@Edge pour modifier le statut d'erreur qui est renvoyé aux utilisateurs.

Exemple : utilisez un déclencheur de réponse d'origine pour mettre à jour le code d'état d'erreur à 200

Cette fonction explique comment vous pouvez mettre à jour le statut de la réponse sur 200 et générer un contenu de corps statique à renvoyer à l'utilisateur dans le scénario suivant :

  • La fonction est déclenchée dans une réponse de l'origine.

  • Le statut de la réponse du serveur d’origine est un code de statut d’erreur (4xx ou 5xx).

Node.js
'use strict'; exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; /** * This function updates the response status to 200 and generates static * body content to return to the viewer in the following scenario: * 1. The function is triggered in an origin response * 2. The response status from the origin server is an error status code (4xx or 5xx) */ if (response.status >= 400 && response.status <= 599) { response.status = 200; response.statusDescription = 'OK'; response.body = 'Body generation example'; } callback(null, response); };
Python
def lambda_handler(event, context): response = event['Records'][0]['cf']['response'] ''' This function updates the response status to 200 and generates static body content to return to the viewer in the following scenario: 1. The function is triggered in an origin response 2. The response status from the origin server is an error status code (4xx or 5xx) ''' if int(response['status']) >= 400 and int(response['status']) <= 599: response['status'] = 200 response['statusDescription'] = 'OK' response['body'] = 'Body generation example' return response

Exemple : utilisez un déclencheur de réponse d'origine pour mettre à jour le code d'état d'erreur à 302

Cette fonction explique comment vous pouvez mettre à jour le code de statut HTTP sur 302 pour rediriger le trafic vers un autre chemin (comportement de cache) qui possède une autre origine configurée. Remarques :

  • La fonction est déclenchée dans une réponse de l'origine.

  • Le statut de la réponse du serveur d’origine est un code de statut d’erreur (4xx ou 5xx).

Node.js
'use strict'; exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const request = event.Records[0].cf.request; /** * This function updates the HTTP status code in the response to 302, to redirect to another * path (cache behavior) that has a different origin configured. Note the following: * 1. The function is triggered in an origin response * 2. The response status from the origin server is an error status code (4xx or 5xx) */ if (response.status >= 400 && response.status <= 599) { const redirect_path = `/plan-b/path?${request.querystring}`; response.status = 302; response.statusDescription = 'Found'; /* Drop the body, as it is not required for redirects */ response.body = ''; response.headers['location'] = [{ key: 'Location', value: redirect_path }]; } callback(null, response); };
Python
def lambda_handler(event, context): response = event['Records'][0]['cf']['response'] request = event['Records'][0]['cf']['request'] ''' This function updates the HTTP status code in the response to 302, to redirect to another path (cache behavior) that has a different origin configured. Note the following: 1. The function is triggered in an origin response 2. The response status from the origin server is an error status code (4xx or 5xx) ''' if int(response['status']) >= 400 and int(response['status']) <= 599: redirect_path = '/plan-b/path?%s' % request['querystring'] response['status'] = 302 response['statusDescription'] = 'Found' # Drop the body as it is not required for redirects response['body'] = '' response['headers']['location'] = [{'key': 'Location', 'value': redirect_path}] return response

Accéder au corps de la demande - exemples

Les exemples de cette section illustrent l'utilisation de Lambda@Edge pour utiliser des demandes POST.

Note

Pour utiliser ces exemples, vous devez activer l'option Inclure le corps dans l'association de fonction Lambda de la distribution. Elle n'est pas activée par défaut.

  • Pour activer ce paramètre dans la CloudFront console, cochez la case Inclure le corps dans l'association de fonctions Lambda.

  • Pour activer ce paramètre dans l' CloudFront API ou avec AWS CloudFormation, définissez le IncludeBody champ sur true inLambdaFunctionAssociation.

Exemple : utiliser un déclencheur de requête pour lire un formulaire HTML

Cette fonction montre comment vous pouvez traiter le corps d'une requête POST générée par un formulaire HTML (formulaire web), tel que « Contactez-nous ». Par exemple, vous pouvez avoir un formulaire HTML comme le suivant :

<html> <form action="https://example.com" method="post"> Param 1: <input type="text" name="name1"><br> Param 2: <input type="text" name="name2"><br> input type="submit" value="Submit"> </form> </html>

Pour l'exemple de fonction qui suit, la fonction doit être déclenchée dans une demande de CloudFront visualisation ou une demande d'origine.

Node.js
'use strict'; const querystring = require('querystring'); /** * This function demonstrates how you can read the body of a POST request * generated by an HTML form (web form). The function is triggered in a * CloudFront viewer request or origin request event type. */ exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; if (request.method === 'POST') { /* HTTP body is always passed as base64-encoded string. Decode it. */ const body = Buffer.from(request.body.data, 'base64').toString(); /* HTML forms send the data in query string format. Parse it. */ const params = querystring.parse(body); /* For demonstration purposes, we only log the form fields here. * You can put your custom logic here. For example, you can store the * fields in a database, such as Amazon DynamoDB, and generate a response * right from your Lambda@Edge function. */ for (let param in params) { console.log(`For "${param}" user submitted "${params[param]}".\n`); } } return callback(null, request); };
Python
import base64 from urllib.parse import parse_qs ''' Say there is a POST request body generated by an HTML such as: <html> <form action="https://example.com" method="post"> Param 1: <input type="text" name="name1"><br> Param 2: <input type="text" name="name2"><br> input type="submit" value="Submit"> </form> </html> ''' ''' This function demonstrates how you can read the body of a POST request generated by an HTML form (web form). The function is triggered in a CloudFront viewer request or origin request event type. ''' def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] if request['method'] == 'POST': # HTTP body is always passed as base64-encoded string. Decode it body = base64.b64decode(request['body']['data']) # HTML forms send the data in query string format. Parse it params = {k: v[0] for k, v in parse_qs(body).items()} ''' For demonstration purposes, we only log the form fields here. You can put your custom logic here. For example, you can store the fields in a database, such as Amazon DynamoDB, and generate a response right from your Lambda@Edge function. ''' for key, value in params.items(): print("For %s use submitted %s" % (key, value)) return request

Exemple : utilisation d'un déclencheur de demande pour modifier un formulaire HTML

Cette fonction montre comment vous pouvez modifier le corps d'une requête POST générée par un formulaire HTML (formulaire web). La fonction est déclenchée dans une demande de CloudFront visualisation ou une demande d'origine.

Node.js
'use strict'; const querystring = require('querystring'); exports.handler = (event, context, callback) => { var request = event.Records[0].cf.request; if (request.method === 'POST') { /* Request body is being replaced. To do this, update the following /* three fields: * 1) body.action to 'replace' * 2) body.encoding to the encoding of the new data. * * Set to one of the following values: * * text - denotes that the generated body is in text format. * Lambda@Edge will propagate this as is. * base64 - denotes that the generated body is base64 encoded. * Lambda@Edge will base64 decode the data before sending * it to the origin. * 3) body.data to the new body. */ request.body.action = 'replace'; request.body.encoding = 'text'; request.body.data = getUpdatedBody(request); } callback(null, request); }; function getUpdatedBody(request) { /* HTTP body is always passed as base64-encoded string. Decode it. */ const body = Buffer.from(request.body.data, 'base64').toString(); /* HTML forms send data in query string format. Parse it. */ const params = querystring.parse(body); /* For demonstration purposes, we're adding one more param. * * You can put your custom logic here. For example, you can truncate long * bodies from malicious requests. */ params['new-param-name'] = 'new-param-value'; return querystring.stringify(params); }
Python
import base64 from urllib.parse import parse_qs, urlencode def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] if request['method'] == 'POST': ''' Request body is being replaced. To do this, update the following three fields: 1) body.action to 'replace' 2) body.encoding to the encoding of the new data. Set to one of the following values: text - denotes that the generated body is in text format. Lambda@Edge will propagate this as is. base64 - denotes that the generated body is base64 encoded. Lambda@Edge will base64 decode the data before sending it to the origin. 3) body.data to the new body. ''' request['body']['action'] = 'replace' request['body']['encoding'] = 'text' request['body']['data'] = getUpdatedBody(request) return request def getUpdatedBody(request): # HTTP body is always passed as base64-encoded string. Decode it body = base64.b64decode(request['body']['data']) # HTML forms send data in query string format. Parse it params = {k: v[0] for k, v in parse_qs(body).items()} # For demonstration purposes, we're adding one more param # You can put your custom logic here. For example, you can truncate long # bodies from malicious requests params['new-param-name'] = 'new-param-value' return urlencode(params)