如何从 Amazon API 网关将参数从 POST 传递到 AWS Lambda
How to pass a params from POST to AWS Lambda from Amazon API Gateway
本题
展示了如何使用 API 网关将查询字符串参数映射到 AWS lambda。我想做同样的事情,但映射 POST 值而不是查询字符串。我试过了:
{
"values": "$input.params()"
}
但没有用,我没有看到实际的表单数据。顺便说一句,我发帖使用:
application/x-www-form-urlencoded
我从我的 lambda 函数得到了响应,所以我知道它可以很好地调用 lambda,但我的问题是我在任何地方都看不到 POST 参数。我不知道如何映射它们。我把我在 Lambda 方面得到的所有东西都扔掉了,这里是:
{"values":"{path={}, querystring={}, header={Accept=*/*, Accept-Encoding=gzip, deflate, Accept-Language=en-US,en;q=0.8, Cache-Control=no-cache, 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/x-www-form-urlencoded, Origin=chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop, Postman-Token=7ba28698-8753-fcb1-1f48-66750ce12ade, Via=1.1 6ba5553fa41dafcdc0e74d152f3a7a75.cloudfront.net (CloudFront), X-Amz-Cf-Id=sc8C7dLcW0BHYopztNYrnddC0hXyFdBzHv0O9aWU1gKhd1D_J2HF3w==, X-Forwarded-For=50.196.93.57, 54.239.140.62, X-Forwarded-Port=443, X-Forwarded-Proto=https}}"}
您可以通过在集成设置中配置映射模板,将任何请求正文数据转换为有效的 JSON 格式,以便 AWS Lambda 可以接收它。
目前Amazon API Gateway官方好像还没有支持application/x-www-form-urlencoded,但是avilewin发布了a solution to do that on the AWS forums. In the mapping templates you can use Velocity Template Language (VTL),所以你需要做的就是配置映射模板转换application/x-www-form-urlencoded 格式转换为有效的 JSON 格式。当然这是一个肮脏的解决方案,但我认为这是目前唯一的方法。
您可以使用 API 网关模板将参数转换为 JSON:
https://forums.aws.amazon.com/thread.jspa?messageID=673012&tstart=0#673012
或者您可以使用 QueryString 解析器包在 lambda 函数本身中执行此操作:https://www.npmjs.com/package/qs
var qs = require('qs');
var obj = qs.parse('a=c'); // { a: 'c' }
如果 Amazon 添加 built-in 对此类功能的支持,我会使用它,但在那之前我个人更喜欢第二种方式,因为如果出现问题,它更干净、更容易调试。
2017 年 7 月更新:
您可以使用默认支持的代理集成:
http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html
r7kamura 的回答很好。此外,这是适用于所有情况(假设 POST)的 application/x-www-form-urlencoded
的可理解且强大的映射模板示例:
{
"data": {
#foreach( $token in $input.path('$').split('&') )
#set( $keyVal = $token.split('=') )
#set( $keyValSize = $keyVal.size() )
#if( $keyValSize >= 1 )
#set( $key = $util.urlDecode($keyVal[0]) )
#if( $keyValSize >= 2 )
#set( $val = $util.urlDecode($keyVal[1]) )
#else
#set( $val = '' )
#end
"$key": "$val"#if($foreach.hasNext),#end
#end
#end
}
}
它将转换
的输入
name=Marcus&email=email%40example.com&message=
进入
{
"data": {
"name": "Marcus",
"email": "email@example.com",
"message": ""
}
}
Lambda 处理程序可以像这样使用它(这个 returns 所有输入数据):
module.exports.handler = function(event, context, cb) {
return cb(null, {
data: event.data
});
};
POST body 将在以下位置提供:
event['body']['param']
GET 参数和 headers 也将通过
可用
event['pathParameters']['param1']
event["queryStringParameters"]['queryparam1']
event['requestContext']['identity']['userAgent']
event['requestContext']['identity']['sourceIP']
这适用于 lambda 集成。
假设您的 POST 请求正文是例如
{
"name" : "Hello",
"address" : "Cool place"
}
您可以像这样访问它:
if (event.body !== null && event.body !== undefined) {
let body = JSON.parse(event.body)
let name = body.name;
let address = body.address;
}
我用 POST 请求实现了 API,其中 Content-Type
是 application/x-www-form-urlencoded
。如果您只是对获取类似于 GET 请求的长值查询字符串感兴趣,请使用此映射语法。
{
"body": "$input.body"
}
请注意,您也可以添加其他映射...我将其省略以解决原始问题。
Here's a blog tutorial 是我最初实现 API 时使用的。然后我的 lambda 函数解析查询字符串,将数据传递给其他进程。
我找到了一个我认为值得分享的非常简单的解决方案,因为我花了一些时间才找到这个最小的工作代码。
如果您有一个通用表单,即发送内容类型为 application/x-www-form-urlencoded 的数据,只需标记 "Lambda proxy integration",然后您将在 event.body 中找到可以解析的编码表单数据Node.js 查询字符串本机模块。
const querystring = require('querystring')
function handler (event, context, callback) {
// Read form data.
const { user, pass } = querystring.parse(event.body)
// Follows your code to handle request.
}
returns 排序发布值字典的简单函数:
import urllib
from collections import OrderedDict
postdata = ''
def GetPostData(body):
#postdata = OrderedDict()
postdata = {}
for items in body.split('&'):
vals = items.split('=')
postdata[vals[0]] = urllib.parse.unquote(vals[1])
return postdata
#Testing it out:
#Assume you get body from event['body'] or body = event.get['body']
body = 'text=This%20works%20really%20well%21%245123%21%403%2146t5%40%2341&anotherkey=isawesome23412%201%21%403%21%40312'
postdata = GetPostData(body)
print(postdata['text'])
#returns 'This works really well!23!@3!46t5@#41'
print(postdata['anotherkey'])
#returns 'isawesome23412 1!@3!@312'
为避免丢失已发布项目时出现关键错误,
您应该改用 value = postdata.get('') ,因为如果密钥不存在,值将为 None。
扩展@markus-whybrow 回答:
{
#foreach( $token in $input.path('$').split('&') )
#set( $keyVal = $token.split('=') )
#set( $keyValSize = $keyVal.size() )
#if( $keyValSize >= 1 )
#set( $key = $util.urlDecode($keyVal[0]) )
#if( $keyValSize >= 2 )
#set( $val = $util.urlDecode($keyVal[1]) )
#else
#set( $val = '' )
#end
"$key": "$util.escapeJavaScript($val)"#if($foreach.hasNext),#end
#end
#end
}
这消除了 "data" 并且还修复了一个情况,如果您在其中一个值中有双引号。
如果您想将 POST 中的所有 body 发送到您的 Lambda 函数,请将此写在 Integration Request
:
{
"values": $input.json('$')
}
如果您想从 body 构建自己的结构,请执行以下操作:
{
"values": {
"body-param1": $input.json('body-param1'),
"others": {
"body-param2": "$input.json('body-param2')",
}
}
}
其中 body-param1 是一个数字,body-param2 是一个字符串。
如果您想发送 headers,请执行以下操作:
{
"headers": {
#foreach($param in $input.params().header.keySet())
"$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext), #end
#end
}
}
2021 年 6 月
application/x-www-form-urlencoded
POST 的映射模板:
(Python)
from base64 import b64decode
from urllib.parse import parse_qs
def lambda_handler(event, context):
params = parse_qs(b64decode(event.get('body')).decode('utf-8'))
print(params.get('name')[0])
print(params.get('email')[0])
同样,使用 params 字典和任何参数名称执行您想执行的任何操作。
这个问题的答案迟到了,但我找到了一个可行的解决方案。在 API 网关中,将 POST 方法添加到资源。在集成请求中,选择 Lambda 函数和 Lambda 代理。
来自测试请求正文部分的 JSON 将直接传递给函数,您可以像这样读取和 return 返回:
const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event, context) => {
console.log('Received event:', JSON.stringify(event, null, 2));
let body;
let statusCode = '200';
const headers = {
'Content-Type': 'application/json',
};
try {
body = JSON.parse(event.body);
} catch (err) {
statusCode = '400';
body = err.message;
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};
本题
展示了如何使用 API 网关将查询字符串参数映射到 AWS lambda。我想做同样的事情,但映射 POST 值而不是查询字符串。我试过了:
{
"values": "$input.params()"
}
但没有用,我没有看到实际的表单数据。顺便说一句,我发帖使用:
application/x-www-form-urlencoded
我从我的 lambda 函数得到了响应,所以我知道它可以很好地调用 lambda,但我的问题是我在任何地方都看不到 POST 参数。我不知道如何映射它们。我把我在 Lambda 方面得到的所有东西都扔掉了,这里是:
{"values":"{path={}, querystring={}, header={Accept=*/*, Accept-Encoding=gzip, deflate, Accept-Language=en-US,en;q=0.8, Cache-Control=no-cache, 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/x-www-form-urlencoded, Origin=chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop, Postman-Token=7ba28698-8753-fcb1-1f48-66750ce12ade, Via=1.1 6ba5553fa41dafcdc0e74d152f3a7a75.cloudfront.net (CloudFront), X-Amz-Cf-Id=sc8C7dLcW0BHYopztNYrnddC0hXyFdBzHv0O9aWU1gKhd1D_J2HF3w==, X-Forwarded-For=50.196.93.57, 54.239.140.62, X-Forwarded-Port=443, X-Forwarded-Proto=https}}"}
您可以通过在集成设置中配置映射模板,将任何请求正文数据转换为有效的 JSON 格式,以便 AWS Lambda 可以接收它。
目前Amazon API Gateway官方好像还没有支持application/x-www-form-urlencoded,但是avilewin发布了a solution to do that on the AWS forums. In the mapping templates you can use Velocity Template Language (VTL),所以你需要做的就是配置映射模板转换application/x-www-form-urlencoded 格式转换为有效的 JSON 格式。当然这是一个肮脏的解决方案,但我认为这是目前唯一的方法。
您可以使用 API 网关模板将参数转换为 JSON: https://forums.aws.amazon.com/thread.jspa?messageID=673012&tstart=0#673012
或者您可以使用 QueryString 解析器包在 lambda 函数本身中执行此操作:https://www.npmjs.com/package/qs
var qs = require('qs');
var obj = qs.parse('a=c'); // { a: 'c' }
如果 Amazon 添加 built-in 对此类功能的支持,我会使用它,但在那之前我个人更喜欢第二种方式,因为如果出现问题,它更干净、更容易调试。
2017 年 7 月更新:
您可以使用默认支持的代理集成: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html
r7kamura 的回答很好。此外,这是适用于所有情况(假设 POST)的 application/x-www-form-urlencoded
的可理解且强大的映射模板示例:
{
"data": {
#foreach( $token in $input.path('$').split('&') )
#set( $keyVal = $token.split('=') )
#set( $keyValSize = $keyVal.size() )
#if( $keyValSize >= 1 )
#set( $key = $util.urlDecode($keyVal[0]) )
#if( $keyValSize >= 2 )
#set( $val = $util.urlDecode($keyVal[1]) )
#else
#set( $val = '' )
#end
"$key": "$val"#if($foreach.hasNext),#end
#end
#end
}
}
它将转换
的输入name=Marcus&email=email%40example.com&message=
进入
{
"data": {
"name": "Marcus",
"email": "email@example.com",
"message": ""
}
}
Lambda 处理程序可以像这样使用它(这个 returns 所有输入数据):
module.exports.handler = function(event, context, cb) {
return cb(null, {
data: event.data
});
};
POST body 将在以下位置提供:
event['body']['param']
GET 参数和 headers 也将通过
可用event['pathParameters']['param1']
event["queryStringParameters"]['queryparam1']
event['requestContext']['identity']['userAgent']
event['requestContext']['identity']['sourceIP']
这适用于 lambda 集成。 假设您的 POST 请求正文是例如
{
"name" : "Hello",
"address" : "Cool place"
}
您可以像这样访问它:
if (event.body !== null && event.body !== undefined) {
let body = JSON.parse(event.body)
let name = body.name;
let address = body.address;
}
我用 POST 请求实现了 API,其中 Content-Type
是 application/x-www-form-urlencoded
。如果您只是对获取类似于 GET 请求的长值查询字符串感兴趣,请使用此映射语法。
{
"body": "$input.body"
}
请注意,您也可以添加其他映射...我将其省略以解决原始问题。
Here's a blog tutorial 是我最初实现 API 时使用的。然后我的 lambda 函数解析查询字符串,将数据传递给其他进程。
我找到了一个我认为值得分享的非常简单的解决方案,因为我花了一些时间才找到这个最小的工作代码。
如果您有一个通用表单,即发送内容类型为 application/x-www-form-urlencoded 的数据,只需标记 "Lambda proxy integration",然后您将在 event.body 中找到可以解析的编码表单数据Node.js 查询字符串本机模块。
const querystring = require('querystring')
function handler (event, context, callback) {
// Read form data.
const { user, pass } = querystring.parse(event.body)
// Follows your code to handle request.
}
returns 排序发布值字典的简单函数:
import urllib
from collections import OrderedDict
postdata = ''
def GetPostData(body):
#postdata = OrderedDict()
postdata = {}
for items in body.split('&'):
vals = items.split('=')
postdata[vals[0]] = urllib.parse.unquote(vals[1])
return postdata
#Testing it out:
#Assume you get body from event['body'] or body = event.get['body']
body = 'text=This%20works%20really%20well%21%245123%21%403%2146t5%40%2341&anotherkey=isawesome23412%201%21%403%21%40312'
postdata = GetPostData(body)
print(postdata['text'])
#returns 'This works really well!23!@3!46t5@#41'
print(postdata['anotherkey'])
#returns 'isawesome23412 1!@3!@312'
为避免丢失已发布项目时出现关键错误, 您应该改用 value = postdata.get('') ,因为如果密钥不存在,值将为 None。
扩展@markus-whybrow 回答:
{
#foreach( $token in $input.path('$').split('&') )
#set( $keyVal = $token.split('=') )
#set( $keyValSize = $keyVal.size() )
#if( $keyValSize >= 1 )
#set( $key = $util.urlDecode($keyVal[0]) )
#if( $keyValSize >= 2 )
#set( $val = $util.urlDecode($keyVal[1]) )
#else
#set( $val = '' )
#end
"$key": "$util.escapeJavaScript($val)"#if($foreach.hasNext),#end
#end
#end
}
这消除了 "data" 并且还修复了一个情况,如果您在其中一个值中有双引号。
如果您想将 POST 中的所有 body 发送到您的 Lambda 函数,请将此写在 Integration Request
:
{
"values": $input.json('$')
}
如果您想从 body 构建自己的结构,请执行以下操作:
{
"values": {
"body-param1": $input.json('body-param1'),
"others": {
"body-param2": "$input.json('body-param2')",
}
}
}
其中 body-param1 是一个数字,body-param2 是一个字符串。
如果您想发送 headers,请执行以下操作:
{
"headers": {
#foreach($param in $input.params().header.keySet())
"$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext), #end
#end
}
}
2021 年 6 月
application/x-www-form-urlencoded
POST 的映射模板:
(Python)
from base64 import b64decode
from urllib.parse import parse_qs
def lambda_handler(event, context):
params = parse_qs(b64decode(event.get('body')).decode('utf-8'))
print(params.get('name')[0])
print(params.get('email')[0])
同样,使用 params 字典和任何参数名称执行您想执行的任何操作。
这个问题的答案迟到了,但我找到了一个可行的解决方案。在 API 网关中,将 POST 方法添加到资源。在集成请求中,选择 Lambda 函数和 Lambda 代理。
来自测试请求正文部分的 JSON 将直接传递给函数,您可以像这样读取和 return 返回:
const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event, context) => {
console.log('Received event:', JSON.stringify(event, null, 2));
let body;
let statusCode = '200';
const headers = {
'Content-Type': 'application/json',
};
try {
body = JSON.parse(event.body);
} catch (err) {
statusCode = '400';
body = err.message;
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};