如何将参数从 POST 从 Amazon API Gateway 传递到 AWS Lambda

Posted

技术标签:

【中文标题】如何将参数从 POST 从 Amazon API Gateway 传递到 AWS Lambda【英文标题】:How to pass a params from POST to AWS Lambda from Amazon API Gateway 【发布时间】:2015-11-10 11:36:18 【问题描述】:

在这个问题How to pass a querystring or route parameter 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"

【问题讨论】:

看看这个教程,相信会有所帮助-snowulf.com/2015/08/05/… 【参考方案1】:

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 处理程序可以像这样使用它(这个返回所有输入数据):

module.exports.handler = function(event, context, cb) 
  return cb(null, 
    data: event.data
  );
;

【讨论】:

伙计,连一个赞成票都没有,这对我来说非常有用,谢谢! 完美运行。在过去的几天里拉了我的头发,试图使用 aws 加载 facebook 画布应用程序。干得好@Marcus 您好!到目前为止,我正在尝试将此解决方案用于 c# Dot.Net Core Lambda 集成,该映射允许请求传递到 lambda。但我的身体总是空的。我尝试构建一个适合表单参数的模型,但无济于事。如果有人通过 c# 成功使用此解决方案,将不胜感激。 我们为什么需要#if($foreach.hasNext),#end @Marcus Whybrow,如何将其集成到 SAM?【参考方案2】:

您可以通过在集成设置中配置映射模板将任何请求正文数据转换为有效的 JSON 格式,以便 AWS Lambda 可以接收它。

目前看来,Amazon API Gateway 还没有正式支持 application/x-www-form-urlencoded,但 avilewin 在 AWS 论坛上发布了 a solution 来做到这一点。在映射模板中可以使用Velocity Template Language (VTL),因此您需要配置映射模板,将application/x-www-form-urlencoded格式转换为有效的JSON格式。当然这是一个肮脏的解决方案,但我认为这是目前唯一的方法。

【讨论】:

这仍然有效,AWS API Gateway 不支持application/x-www-form-urlencoded? 我也很想知道这一点! 据我所知,叹息。今天花了几个小时在这上面。说真的,AWS 的小丑忽略了将参数发布到处理程序的最基本形式的 webhook。【参考方案3】:

如果您启用 Lambda 代理集成

POST 正文可从以下位置获得:

event['body']['param']

GET 参数和标头也可以通过

获得
event['pathParameters']['param1']
event["queryStringParameters"]['queryparam1']
event['requestContext']['identity']['userAgent']
event['requestContext']['identity']['sourceIP']

【讨论】:

event.body 返回id="some",但无法通过event.body.id 获得id 或您所写的方式。 event['body'] (和其他人)抛出 KeyError,@Jonathan 你能详细说明一下这是如何工作的吗?我正在尝试将一个变量从 URL 传递给 lambda 处理程序,然后它会使用该变量来填写我想要发出请求的 URL。【参考方案4】:

您可以使用 API 网关模板将参数转换为 JSON: https://forums.aws.amazon.com/thread.jspa?messageID=673012&tstart=0#673012

或者您可以在 lambda 函数本身中使用 QueryString parser pacakge 执行此操作:https://www.npmjs.com/package/qs

var qs = require('qs');
var obj = qs.parse('a=c');  //  a: 'c'  

如果亚马逊添加了对此类功能的内置支持,我将使用它,但在此之前我个人更喜欢第二种方式,因为如果出现问题,它更清洁且更容易调试。

2017 年 7 月更新

您可以使用默认支持的代理集成: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html

【讨论】:

【参考方案5】:

扩展@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
    

这消除了“数据”,并且如果您的某个值中有双引号,也可以解决一个案例。

【讨论】:

如果你有数组参数怎么办?这将最终在 lambda 函数中成为一个字符串键,例如: key1: 'value1', key2: value2', 'array_key[][something]': 'some array value' 。在这种情况下,我们必须做一些额外的解析,对吧? @Dianna 你找到解决这个问题的方法了吗? @real_shardul 我想我做到了,但我无法告诉你解决方案是什么,因为: 1. 我不记得了; 2. 我无法再访问那个 lambda 函数和 aws 帐户了。 1 年发生了很多事情 :)【参考方案6】:

我发现了一个非常简单的解决方案,我认为值得分享,因为我花了一些时间才找到这个最小的工作代码。

如果您有一个通用表单,发送内容类型为 application/x-www-form-urlencoded 的数据,只需标记“Lambda 代理集成”,那么您将在 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.

【讨论】:

【参考方案7】:

我实现了一个带有 POST 请求的 API,其中 Content-Typeapplication/x-www-form-urlencoded。如果您只是对获取类似于 GET 请求的长查询字符串感兴趣,请使用此映射语法。


    "body": "$input.body"

注意,您也可以添加其他映射...我将其省略以解决原始问题。

Here's a blog tutorial 最初实现我的 API 时使用的。然后我的 lambda 函数解析查询字符串,将数据传递给其他进程。

【讨论】:

【参考方案8】:

这适用于 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;

更多信息在这里:http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html

【讨论】:

【参考方案9】:

如果您想通过 POST 将所有正文发送到您的 Lambda 函数,请在Integration Request 写下:


    "values": $input.json('$')

如果您想从主体构建自己的结构,请执行以下操作:


    "values": 
        "body-param1": $input.json('body-param1'),
        "others": 
            "body-param2": "$input.json('body-param2')",
        
    

body-param1 是一个数字,body-param2 是一个字符串。

如果您想发送标头,请执行以下操作:


    "headers": 
        #foreach($param in $input.params().header.keySet())
            "$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext), #end
        #end
    

【讨论】:

【参考方案10】:

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 字典和参数名称执行任何您想要执行的操作。

【讨论】:

【参考方案11】:

返回已发布值的有序字典的简单函数:

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!$5123!@3!46t5@#41'
print(postdata['anotherkey'])
#returns 'isawesome23412 1!@3!@312'

为避免在发布的项目丢失时出现关键错误, 您应该改用 value = postdata.get('') ,因为如果键不存在,则 value 将为 None。

【讨论】:

以上是关于如何将参数从 POST 从 Amazon API Gateway 传递到 AWS Lambda的主要内容,如果未能解决你的问题,请参考以下文章

如何将 JSON 作为参数传递给控制器​​ .net api 中的 Post 方法

如何使用 Amazon Alexa 访问本地 API

将多个对象从Angular控制器POST到Web API 2

使用 amazon sdk 和存储桶策略从 ios 应用程序将图像上传到 amazon s3

如何从 REST API 传递类别属性值

从 Amazon Product API 获取 Kindle 电子书的标价