저는 현재 NodeJS를 사용하여 AWS Api Gateway를 통해 AWS Lambda에 봇을 구축하고 있으며 POST 요청 및 JSON 데이터에 문제가 있습니다. 내 API는 ‘Lambda 프록시 통합 사용’을 사용하며 프록시가 Application / json의 콘텐츠 유형과 본문의 일부 json을 테스트 할 때도 예를 들어 {"foo":"bar"}
먼저 파싱하지 않고는 객체에 액세스 할 수 없습니다.
예 :
var json = JSON.parse(event.body);
console.log(json.foo);
이제는 이것이 JSON.parse를 통해 실행하는 것이 큰 문제가 아니라는 것을 알고 있지만 전혀 그렇지 않은 다른 여러 예제를 보았습니다. 여기를 참조하십시오 https://github.com/pinzler/fb-messenger-bot-aws-lambda/blob/master/index.js
이 문제를 올바르게 처리하려면 API 게이트웨이에 추가해야합니까? ‘post method request’섹션의 ‘request body’단계에는 요청 본문에 대한 콘텐츠 유형의 application / json 설정이 있습니다.
위의 예제에 대한 추가 정보는 내가 말할 수있는 한 프록시 통합을 사용하지 않는 것 같아서 여기서 무엇을해야할지 잘 모르겠습니다.
답변
Lambda 통합 및 Lambda 프록시 통합과 같이 API Gateway에서 구성 할 수있는 두 가지 Lambda 통합이 있습니다. 들어 람다 통합 , 당신은 당신이 몸을 구문 분석 할 필요가 없습니다 페이로드에 람다에 전달할 것, 그러나 당신이 사용하는 경우 어떤 사용자 정의 할 수 있습니다 람다 프록시 통합 API 게이트웨이에서, API 게이트웨이 것이다 페이로드 람다에 프록시 모든 이렇게
{
"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
}
}
참조하는 예의 경우 원래 요청에서 본문을 가져 오지 않습니다. API Gateway에 대한 응답 본문을 다시 구성하고 있습니다. 이 형식이어야합니다.
{
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "...",
"isBase64Encoded": false
}
답변
Lambda와 API Gateway 통합 작업을 할 때 이해해야 할 몇 가지 사항이 있다고 생각합니다.
Lambda 통합과 Lambda 프록시 통합
이전에는 매핑 템플릿이 필요한 Lambda 통합 만있었습니다. 이것이 여전히 많은 예제를 사용하는 이유라고 생각합니다.
-
Amazon API Gateway에서 AWS Lambda로 쿼리 문자열 또는 라우팅 파라미터를 전달하는 방법
2017 년 9 월부터는 요청 본문에 액세스하기 위해 더 이상 매핑을 구성 할 필요가 없습니다.
-
Lambda 프록시 통합, 활성화하면 API Gateway는 모든 요청을 JSON에 매핑하고 이벤트 객체로 Lambda에 전달합니다. Lambda 함수에서 쿼리 문자열 파라미터, 헤더, 단계 변수, 경로 파라미터, 요청 컨텍스트 및 본문을 검색 할 수 있습니다.
Lambda 프록시 통합을 활성화하지 않으면 API Gateway의 통합 요청 섹션에서 매핑 템플릿을 생성하고 HTTP 요청을 JSON에 매핑하는 방법을 직접 결정해야합니다. 그리고 정보를 클라이언트로 다시 전달하려면 통합 응답 매핑을 만들어야 할 것입니다.
Lambda 프록시 통합이 추가되기 전에 사용자는 요청과 응답을 수동으로 매핑해야했는데, 이는 특히 더 복잡한 매핑 에서 당황 스러웠습니다 .
본문은 JSON이 아닌 이스케이프 된 문자열입니다.
Lambda 프록시 통합을 사용하면 람다의 경우 본문이 JSON이 아니라 백 슬래시로 이스케이프 된 문자열입니다.
"body": "{\"foo\":\"bar\"}"
JSON 포맷터에서 테스트 한 경우.
Parse error on line 1:
{\"foo\":\"bar\"}
-^
Expecting 'STRING', '}', got 'undefined'
아래 문서는 응답에 관한 문서이지만 요청에 적용해야합니다.
- Amazon API Gateway에서 “잘못된 Lambda 프록시 응답”오류 또는 502 상태 코드를 받았습니다. 이 문제를 어떻게 해결합니까?
JSON을 반환하는 경우 본문 필드는 문자열로 변환해야합니다. 그렇지 않으면 응답에 추가 문제가 발생합니다. JSON.stringify를 사용하여 Node.js 함수에서이를 처리 할 수 있습니다. 다른 런타임에는 다른 솔루션이 필요하지만 개념은 동일합니다.
JavaScript가 JSON 개체로 액세스하려면 JapaScript의 json.parse, Python의 json.dumps를 사용하여 JSON 개체로 다시 변환해야합니다.
- JavaScript에서 JSON으로 작업하는 방법
문자열은 전송에 유용하지만 클라이언트 및 / 또는 서버 측에서 다시 JSON 개체로 변환 할 수 있기를 원할 것 입니다.
AWS 문서 가 무엇을해야 하는지를 보여줍니다.
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);
답변
저는 Zappa와 함께 lambda를 사용하고 있습니다. json 형식으로 POST로 데이터를 보내고 있습니다.
basic_lambda_pure.py에 대한 내 코드는 다음과 같습니다.
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'}}
다음 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
}
내 데이터는 본문 키에 있지만 code64로 인코딩되어 있습니다. 어떻게 알 수 있습니까? 키 isBase64Encoded 봤어요
본문 키 의 값을 복사 하고이 도구 와 “유레카”로 디코딩 하면 값을 얻습니다.
도움이 되었기를 바랍니다. 🙂