我目前正在使用NodeJS通过AWS Api Gateway在AWS lambda上构建机器人,我遇到了POST请求和JSON数据的问题。我的api使用'使用Lambda代理集成',即使我测试代理发送内容类型的Application / json和一些json在体内,例如{"foo":"bar"}
我无法在不解析它的情况下访问该对象
e.g
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设置。
上面示例的自述文件似乎没有使用代理集成,因为我可以告诉所以我不确定我应该在这做什么
答案 0 :(得分:37)
您可以在API网关中配置两种不同的Lambda集成,例如Lambda集成和Lambda代理集成。对于 Lambda集成,您可以在有效负载中自定义要传递给Lambda的内容,而不需要解析正文,但是当您使用 Lambda代理集成时在API网关中,API网关会将所有内容代理到有效负载中的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
}
}
对于您正在引用的示例,它不会从原始请求中获取正文。它正在将响应主体构建回API网关。它应该采用这种格式,
{
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "...",
"isBase64Encoded": false
}
答案 1 :(得分:18)
我认为与Lambda进行API网关集成时需要了解一些事情。
过去只有Lambda集成需要映射模板。我想这就是为什么仍然看到很多使用它的例子。
How to pass a querystring or route parameter to AWS Lambda from Amazon API Gateway
从2017年9月开始,您不再需要配置映射来访问请求正文。
Serverless Architecture on AWS
Lambda代理集成,如果启用它,API Gateway会将每个请求映射到JSON并将其作为事件对象传递给Lambda。在Lambda函数中,您可以从中检索查询字符串参数,标头,阶段变量,路径参数,请求上下文以及正文。
在未启用Lambda代理集成的情况下,您必须在API Gateway的“集成请求”部分中创建映射模板,并决定如何自行将HTTP请求映射到JSON。如果要将信息传递回客户端,您可能必须创建一个集成响应映射。
在添加Lambda代理集成之前,用户被迫手动映射请求和响应,这是令人震惊的原因,尤其是对于更复杂的映射。
使用Lambda代理集成,发生lambda时,主体是使用反斜杠转义的字符串,而不是JSON。
"body": "{\"foo\":\"bar\"}"
如果在JSON格式程序中进行了测试。
Parse error on line 1:
{\"foo\":\"bar\"}
-^
Expecting 'STRING', '}', got 'undefined'
以下文档是关于回复的,但应适用于请求。
如果返回的是JSON,则必须将body字段转换为字符串,否则它将导致响应进一步出现问题。您可以使用JSON.stringify在Node.js函数中进行处理;其他运行时将需要不同的解决方案,但是概念是相同的。
要使JavaScript以JSON对象的形式访问它,需要将其转换回JSON对象,其中JapaScript中为json.parse,Python中为json.dumps。
字符串对于传输非常有用,但是您希望能够在客户端和/或服务器端将其转换回JSON对象。
AWS documentation显示了要做什么。
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);
答案 2 :(得分:1)
我正在使用lambda和Zappa; 我用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
}
我的数据在 body 键上,但是是code64编码的,我怎么知道这个?我看到了键 isBase64Encoded
我复制 body 键的值并使用This tool和" eureka"解码,我得到了值。
我希望这对你有所帮助。 :)
答案 3 :(得分:0)
您可能忘记了定义Content-Type
标头。例如:
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ items }),
}