通过 API 网关在 aws Lambda 中获取 json 正文
Getting json body in aws Lambda via API gateway
我目前正在使用 NodeJS 通过 AWS Api 网关在 AWS lambda 上构建一个机器人,我 运行 遇到了 POST 请求和 JSON 数据。我的 api 使用 'Use Lambda Proxy integration' 甚至当我测试代理发送 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 内容类型。
据我所知,上面示例的自述文件似乎没有使用代理集成,所以我不确定我应该在这里做什么
您可以在 API 网关中配置两种不同的 Lambda 集成:
对于 Lambda non-proxy 集成,您可以在不需要解析正文的有效载荷中自定义要传递给 Lambda 的内容,但是当您在 API 网关中使用 Lambda 代理集成 时,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
}
我在 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
}
我的数据在 body 键上,但是是 code64 编码的,我怎么知道呢?我看到了密钥 isBase64Encoded
我复制了 body 键的值并用 This tool 和 "eureka" 解码,我得到了值。
希望对您有所帮助。 :)
我认为在使用 API 网关与 Lambda 集成时需要了解一些事情。
Lambda 集成与 Lambda 代理集成
过去只有 Lambda 集成需要映射模板。我想这就是为什么仍然看到许多使用它的例子的原因。
As of September 2017, you no longer have to configure mappings to access the request body.
Lambda Proxy Integration, If you enable it, API Gateway will map every request to JSON and pass it to Lambda as the event object. In the Lambda function you’ll be able to retrieve query string parameters, headers, stage variables, path parameters, request context, and the body from it.
Without enabling Lambda Proxy Integration, you’ll have to create a mapping template in the Integration Request section of API Gateway and decide how to map the HTTP request to JSON yourself. And you’d likely have to create an Integration Response mapping if you were to pass information back to the client.
Before Lambda Proxy Integration was added, users were forced to map requests and responses manually, which was a source of consternation, especially with more complex mappings.
文字需要引导思维。弄清楚术语。
Lambda 代理集成 = 通过
只需将 HTTP 请求传递给 lambda。
Lambda 集成 = 模板转换
使用Apache Velocity template完成一个转换过程,需要自己编写模板。
body 是转义字符串,不是 JSON
使用 Lambda 代理集成,lambda 事件中的正文是用反斜杠转义的字符串,而不是 JSON。
"body": "{\"foo\":\"bar\"}"
如果在 JSON 格式化程序中测试。
Parse error on line 1:
{\"foo\":\"bar\"}
-^
Expecting 'STRING', '}', got 'undefined'
下面的文档是关于响应的,但它应该适用于请求。
The body field, if you are returning JSON, must be converted to a string or it will cause further problems with the response. You can use JSON.stringify to handle this in Node.js functions; other runtimes will require different solutions, but the concept is the same.
为了 JavaScript 将其作为 JSON 对象访问,需要在 JapaScript 中使用 json.parse 将其转换回 JSON 对象,在 JapaScript 中使用 json.dumps Python.
Strings are useful for transporting but you’ll want to be able to convert them back to a JSON object on the client and/or the server side.
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);
您可能忘记定义 Content-Type
header。例如:
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ items }),
}
如果您使用的是 Lambda 代理集成,则需要为 JavaScript 使用 JSON.parse(event.body)
或为 Python 使用 json.loads(event["body"])
。
您正在查看的其他示例是针对 AWS 服务 Lambda 集成(不同于 Lambda 代理集成),他们自己构建了事件模板。
有关 Lambda 代理集成结构的更多详细信息,请参阅
我目前正在使用 NodeJS 通过 AWS Api 网关在 AWS lambda 上构建一个机器人,我 运行 遇到了 POST 请求和 JSON 数据。我的 api 使用 'Use Lambda Proxy integration' 甚至当我测试代理发送 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 内容类型。
据我所知,上面示例的自述文件似乎没有使用代理集成,所以我不确定我应该在这里做什么
您可以在 API 网关中配置两种不同的 Lambda 集成:
对于 Lambda non-proxy 集成,您可以在不需要解析正文的有效载荷中自定义要传递给 Lambda 的内容,但是当您在 API 网关中使用 Lambda 代理集成 时,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
}
我在 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
}
我的数据在 body 键上,但是是 code64 编码的,我怎么知道呢?我看到了密钥 isBase64Encoded
我复制了 body 键的值并用 This tool 和 "eureka" 解码,我得到了值。
希望对您有所帮助。 :)
我认为在使用 API 网关与 Lambda 集成时需要了解一些事情。
Lambda 集成与 Lambda 代理集成
过去只有 Lambda 集成需要映射模板。我想这就是为什么仍然看到许多使用它的例子的原因。
As of September 2017, you no longer have to configure mappings to access the request body.
Lambda Proxy Integration, If you enable it, API Gateway will map every request to JSON and pass it to Lambda as the event object. In the Lambda function you’ll be able to retrieve query string parameters, headers, stage variables, path parameters, request context, and the body from it.
Without enabling Lambda Proxy Integration, you’ll have to create a mapping template in the Integration Request section of API Gateway and decide how to map the HTTP request to JSON yourself. And you’d likely have to create an Integration Response mapping if you were to pass information back to the client.
Before Lambda Proxy Integration was added, users were forced to map requests and responses manually, which was a source of consternation, especially with more complex mappings.
文字需要引导思维。弄清楚术语。
Lambda 代理集成 = 通过
只需将 HTTP 请求传递给 lambda。Lambda 集成 = 模板转换
使用Apache Velocity template完成一个转换过程,需要自己编写模板。
body 是转义字符串,不是 JSON
使用 Lambda 代理集成,lambda 事件中的正文是用反斜杠转义的字符串,而不是 JSON。
"body": "{\"foo\":\"bar\"}"
如果在 JSON 格式化程序中测试。
Parse error on line 1:
{\"foo\":\"bar\"}
-^
Expecting 'STRING', '}', got 'undefined'
下面的文档是关于响应的,但它应该适用于请求。
The body field, if you are returning JSON, must be converted to a string or it will cause further problems with the response. You can use JSON.stringify to handle this in Node.js functions; other runtimes will require different solutions, but the concept is the same.
为了 JavaScript 将其作为 JSON 对象访问,需要在 JapaScript 中使用 json.parse 将其转换回 JSON 对象,在 JapaScript 中使用 json.dumps Python.
Strings are useful for transporting but you’ll want to be able to convert them back to a JSON object on the client and/or the server side.
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);
您可能忘记定义 Content-Type
header。例如:
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ items }),
}
如果您使用的是 Lambda 代理集成,则需要为 JavaScript 使用 JSON.parse(event.body)
或为 Python 使用 json.loads(event["body"])
。
您正在查看的其他示例是针对 AWS 服务 Lambda 集成(不同于 Lambda 代理集成),他们自己构建了事件模板。
有关 Lambda 代理集成结构的更多详细信息,请参阅