J'utilise actuellement NodeJS pour créer un bot sur AWS lambda via AWS Api Gateway et je rencontre un problème avec les demandes POST et les données JSON. Mon API utilise "Utiliser l'intégration du proxy Lambda" et même lorsque je teste le proxy en envoyant un type de contenu Application/json et un json dans le corps, par exemple {"foo":"bar"}
je ne peux pas accéder à l'objet sans l'avoir analysé au préalable.
par exemple
var json = JSON.parse(event.body);
console.log(json.foo);
Maintenant, je sais que cela ne semble pas être un problème, mais de le faire via JSON.parse, mais j'ai vu un certain nombre d'autres exemples où ce n'est pas du tout le cas. voir ici https://github.com/pinzler/fb-messenger-bot-aws-lambda/blob/master/index.js
Dois-je ajouter quelque chose à ma passerelle API pour gérer cela correctement? Mon étape 'corps de la demande' dans la section 'demande de méthode postée' a un type de contenu d'application/json configuré pour le corps de la demande.
Le readme de l'exemple ci-dessus ne semble pas utiliser l'intégration de proxy autant que je sache, donc je ne suis pas sûr de ce que je devrais faire ici.
Il existe deux intégrations Lambda différentes que vous pouvez configurer dans API Gateway, telles que l’intégration Lambda et l’intégration de proxy Lambda. Pour intégration Lambda, vous pouvez personnaliser ce que vous allez transmettre à Lambda dans la charge utile dont vous n'avez pas besoin pour analyser le corps, mais lorsque vous utilisez intégration du proxy Lambda = Dans API Gateway, API Gateway utilisera un proxy tel quel pour Lambda,
{
"message": "Hello me!",
"input": {
"path": "/test/hello",
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, lzma, sdch, br",
"Accept-Language": "en-US,en;q=0.8",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Host": "wt6mne2s9k.execute-api.us-west-2.amazonaws.com",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
"Via": "1.1 fb7cca60f0ecd82ce07790c9c5eef16c.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "nBsWBOrSHMgnaROZJK1wGCZ9PcRcSpq_oSXZNQwQ10OTZL4cimZo3g==",
"X-Forwarded-For": "192.168.100.1, 192.168.1.1",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"pathParameters": {"proxy": "hello"},
"requestContext": {
"accountId": "123456789012",
"resourceId": "us4z18",
"stage": "test",
"requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9",
"identity": {
"cognitoIdentityPoolId": "",
"accountId": "",
"cognitoIdentityId": "",
"caller": "",
"apiKey": "",
"sourceIp": "192.168.100.1",
"cognitoAuthenticationType": "",
"cognitoAuthenticationProvider": "",
"userArn": "",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
"user": ""
},
"resourcePath": "/{proxy+}",
"httpMethod": "GET",
"apiId": "wt6mne2s9k"
},
"resource": "/{proxy+}",
"httpMethod": "GET",
"queryStringParameters": {"name": "me"},
"stageVariables": {"stageVarName": "stageVarValue"},
"body": "{\"foo\":\"bar\"}",
"isBase64Encoded": false
}
}
Pour l'exemple que vous référencez, il ne s'agit pas d'obtenir le corps de la demande d'origine. Il reconstruit le corps de la réponse à API Gateway. Il devrait être dans ce format,
{
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "...",
"isBase64Encoded": false
}
Je pense qu'il y a quelques points à comprendre lors de l'utilisation de l'intégration d'API Gateway avec Lambda.
Auparavant, il n'y avait que l'intégration Lambda, qui nécessite des modèles de mappage. Je suppose que c’est la raison pour laquelle je vois encore de nombreux exemples l’utiliser.
À partir de septembre 2017, vous n'avez plus besoin de configurer les mappages pour accéder au corps de la demande.
Architecture sans serveur sur AWS
Intégration du proxy Lambda, si vous l'activez, API Gateway mappera chaque demande sur JSON et la transmettra à Lambda en tant qu'objet événement. Dans la fonction Lambda, vous pourrez récupérer les paramètres de chaîne de requête, les en-têtes, les variables d'étape, les paramètres de chemin, le contexte de la requête et le corps de cette requête.
Sans activer l’intégration du proxy Lambda, vous devez créer un modèle de mappage dans la section Demande d’intégration de la passerelle API et décider comment mapper vous-même la demande HTTP à JSON. Et vous devrez probablement créer un mappage Integration Response si vous deviez transmettre des informations au client.
Avant l’ajout de Lambda Proxy Integration, , les utilisateurs étaient obligés de mapper les demandes et les réponses manuellement, ce qui était une source de consternation , en particulier avec plus de fonctionnalités. mappages complexes.
En utilisant l’intégration du proxy Lambda, le corps dans l’événement de lambda est une chaîne contenant une barre oblique inversée, pas un JSON.
"body": "{\"foo\":\"bar\"}"
Si testé dans un formateur JSON.
Parse error on line 1:
{\"foo\":\"bar\"}
-^
Expecting 'STRING', '}', got 'undefined'
Le document ci-dessous concerne la réponse, mais il devrait s'appliquer à la demande.
Si vous renvoyez du JSON, le champ body doit être converti en chaîne, sinon la réponse posera d'autres problèmes. Vous pouvez utiliser JSON.stringify pour gérer cela dans les fonctions Node.js; d'autres exécutions nécessiteront des solutions différentes, mais le concept est le même.
Pour que JavaScript y ait accès en tant qu’objet JSON, vous devez le reconvertir en objet JSON avec json.parse dans JapaScript, json.dumps en Python.
Les chaînes sont utiles pour le transport mais vous souhaiterez pouvoir les reconvertir en objet JSON côté client et/ou serveur.
Le documentation AWS montre ce qu'il faut faire.
if (event.body !== null && event.body !== undefined) {
let body = JSON.parse(event.body)
if (body.time)
time = body.time;
}
...
var response = {
statusCode: responseCode,
headers: {
"x-custom-header" : "my custom header value"
},
body: JSON.stringify(responseBody)
};
console.log("response: " + JSON.stringify(response))
callback(null, response);
J'utilise lambda avec Zappa; J'envoie des données avec POST au format json:
Mon code pour basic_lambda_pure.py est:
import time
import requests
import json
def my_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
print("Log stream name:", context.log_stream_name)
print("Log group name:", context.log_group_name)
print("Request ID:", context.aws_request_id)
print("Mem. limits(MB):", context.memory_limit_in_mb)
# Code will execute quickly, so we add a 1 second intentional delay so you can see that in time remaining value.
print("Time remaining (MS):", context.get_remaining_time_in_millis())
if event["httpMethod"] == "GET":
hub_mode = event["queryStringParameters"]["hub.mode"]
hub_challenge = event["queryStringParameters"]["hub.challenge"]
hub_verify_token = event["queryStringParameters"]["hub.verify_token"]
return {'statusCode': '200', 'body': hub_challenge, 'headers': 'Content-Type': 'application/json'}}
if event["httpMethod"] == "post":
token = "xxxx"
params = {
"access_token": token
}
headers = {
"Content-Type": "application/json"
}
_data = {"recipient": {"id": 1459299024159359}}
_data.update({"message": {"text": "text"}})
data = json.dumps(_data)
r = requests.post("https://graph.facebook.com/v2.9/me/messages",params=params, headers=headers, data=data, timeout=2)
return {'statusCode': '200', 'body': "ok", 'headers': {'Content-Type': 'application/json'}}
J'ai eu la prochaine réponse JSON:
{
"resource": "/",
"path": "/",
"httpMethod": "POST",
"headers": {
"Accept": "*/*",
"Accept-Encoding": "deflate, gzip",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Content-Type": "application/json",
"Host": "ox53v9d8ug.execute-api.us-east-1.amazonaws.com",
"Via": "1.1 f1836a6a7245cc3f6e190d259a0d9273.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "LVcBZU-YqklHty7Ii3NRFOqVXJJEr7xXQdxAtFP46tMewFpJsQlD2Q==",
"X-Amzn-Trace-Id": "Root=1-59ec25c6-1018575e4483a16666d6f5c5",
"X-Forwarded-For": "69.171.225.87, 52.46.17.84",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https",
"X-Hub-Signature": "sha1=10504e2878e56ea6776dfbeae807de263772e9f2"
},
"queryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"path": "/dev",
"accountId": "001513791584",
"resourceId": "i6d2tyihx7",
"stage": "dev",
"requestId": "d58c5804-b6e5-11e7-8761-a9efcf8a8121",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"apiKey": "",
"sourceIp": "69.171.225.87",
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": null,
"user": null
},
"resourcePath": "/",
"httpMethod": "POST",
"apiId": "ox53v9d8ug"
},
"body": "eyJvYmplY3QiOiJwYWdlIiwiZW50cnkiOlt7ImlkIjoiMTA3OTk2NDk2NTUxMDM1IiwidGltZSI6MTUwODY0ODM5MDE5NCwibWVzc2FnaW5nIjpbeyJzZW5kZXIiOnsiaWQiOiIxNDAzMDY4MDI5ODExODY1In0sInJlY2lwaWVudCI6eyJpZCI6IjEwNzk5NjQ5NjU1MTAzNSJ9LCJ0aW1lc3RhbXAiOjE1MDg2NDgzODk1NTUsIm1lc3NhZ2UiOnsibWlkIjoibWlkLiRjQUFBNHo5RmFDckJsYzdqVHMxZlFuT1daNXFaQyIsInNlcSI6MTY0MDAsInRleHQiOiJob2xhIn19XX1dfQ==",
"isBase64Encoded": true
}
mes données étaient sur la clé du corps , mais le code 64 est-il codé? Comment puis-je savoir cela? J'ai vu la clé isBase64Encoded
Je copie la valeur de corps clé et décode avec cet outil et "eureka", je récupère les valeurs.
J'espère que cela vous aidera. :)