如何从亚马逊API网关传递查询字符串或路由参数到AWS Lambda

例如,如果我们想用

GET /user?name=bob

GET /user/bob

如何将这两个例子作为参数传递给Lambda函数?

我在文档中看到了一些关于设置“映射from”的内容,但我在API Gateway控制台中找不到该设置。

  • method.request.path.parameter-name用于在方法请求页中定义的名为parameter-name的路径参数。
  • method.request.querystring.parameter-name用于在方法请求页中定义的名为parameter-name的查询字符串参数。

尽管我定义了一个查询字符串,但我没有看到这两个选项。

409321 次浏览

让它工作的步骤是:

在API网关控制台中…

  1. Resources -> Integration Request
  2. 点击模板下拉菜单旁边的加号或编辑图标(我知道很奇怪,因为模板字段已经打开了,这里的按钮看起来是灰色的)
  3. 在content-type字段中显式地键入application/json,即使它显示了默认值(如果你不这样做,它将不会保存,也不会给你一个错误消息)
  4. 把它放在输入映射{ "name": "$input.params('name')" }

  5. 点击模板下拉框旁边的复选框(我假设这是最终保存它)

在尝试回答我自己的一个问题时,我发现了这个技巧。

在API Gateway映射模板中,使用下面的代码来给出HTTP客户端发送的完整查询字符串:

{
"querystring": "$input.params().querystring"
}

这样做的好处是,您不必在查询字符串中限制自己使用一组预定义的映射键。现在您可以接受查询字符串中的任何键值对,如果这是您想要的处理方式的话。

注意:根据,只有$input.params(x)被列为VTL模板可用的变量。内部可能会发生变化,querystring可能不再可用。

为了将参数传递给lambda函数,您需要在API Gateway请求和lambda函数之间创建映射。映射在所选API Gateway资源的Integration Request -> Mapping templates部分中完成。

创建类型为application/json的映射,然后在右侧编辑(单击铅笔)模板。

映射模板实际上是一个Velocity模板,你可以使用if,循环,当然还可以打印变量。模板有这些变量被注入,你可以单独访问查询字符串参数,请求头等。使用下面的代码,您可以重新创建整个查询字符串:

{
"querystring" : "#foreach($key in $input.params().querystring.keySet())#if($foreach.index > 0)&#end$util.urlEncode($key)=$util.urlEncode($input.params().querystring.get($key))#end",
"body" : $input.json('$')
}

注意:点击复选符号保存模板。您可以使用资源中的“test”按钮测试更改。但是为了在AWS控制台中测试查询字符串参数,你需要在资源的Method Request部分中定义参数名。

注意:查看Velocity用户指南以获得关于Velocity模板语言的更多信息。

然后在你的lambda模板中,你可以执行以下操作来解析查询字符串:

var query = require('querystring').parse(event.querystring)
// access parameters with query['foo'] or query.foo

接受的答案对我来说很好,但是扩展gimenete的答案,我想要一个通用的模板,我可以用它来传递所有的查询/路径/头参数(目前只是字符串),我得到了下面的模板。我把它贴在这里,以防有人觉得有用:

#set($keys = [])
#foreach($key in $input.params().querystring.keySet())
#set($success = $keys.add($key))
#end


#foreach($key in $input.params().headers.keySet())
#if(!$keys.contains($key))
#set($success = $keys.add($key))
#end
#end


#foreach($key in $input.params().path.keySet())
#if(!$keys.contains($key))
#set($success = $keys.add($key))
#end
#end


{
#foreach($key in $keys)
"$key": "$util.escapeJavaScript($input.params($key))"#if($foreach.hasNext),#end
#end
}

我已经使用这个映射模板为Lambda事件提供了Body、Headers、Method、Path和URL查询字符串参数。我写了一篇博客文章更详细地解释了这个模板:http://kennbrodhagen.net/2015/12/06/how-to-create-a-request-object-for-your-lambda-event-from-api-gateway/

下面是你可以使用的映射模板:

{
"method": "$context.httpMethod",
"body" : $input.json('$'),
"headers": {
#foreach($param in $input.params().header.keySet())
"$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext),#end


#end
},
"queryParams": {
#foreach($param in $input.params().querystring.keySet())
"$param": "$util.escapeJavaScript($input.params().querystring.get($param))" #if($foreach.hasNext),#end


#end
},
"pathParams": {
#foreach($param in $input.params().path.keySet())
"$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end


#end
}
}

如今,AWS上的API Gateway控制台中包含了一个下拉模板。

对于您的API,单击资源名称…然后

展开“Body Mapping Templates”

输入

application / json

为Content-Type(必须显式地输入),并单击勾

一个新窗口将打开,显示“生成模板”和一个下拉菜单(见图)。

选择

请求传递

enter image description here

然后点击保存

要访问任何变量,只需使用以下语法(这是Python) 例如URL: < / p >
https://yourURL.execute-api.us-west-2.amazonaws.com/prod/confirmReg?token=12345&uid=5

可以得到如下变量:

from __future__ import print_function


import boto3
import json


print('Loading function')




def lambda_handler(event, context):
print(event['params']['querystring']['token'])
print(event['params']['querystring']['uid'])

因此,不需要显式地命名或映射您想要的每个变量。

这里的很多答案都很棒。但我想要简单一点的东西。 我想要一些东西,将与“Hello World”样本免费工作。这意味着我想要一个简单的生成一个匹配查询字符串的请求体:

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

我认为上面的答案在构建一些真实的东西时产生了一些更有用的东西,但是对于使用AWS的模板快速运行一个hello世界来说,这非常有用。

查询字符串可以直接在lambda中用javascript解析

GET /user?name =鲍勃

 var name = event.queryStringParameters.name;

但是,这并不能解决GET用户/bob的问题。

下面的参数映射示例通过JSON有效负载将所有参数(包括路径、查询字符串和报头)传递给集成端点

#set($allParams = $input.params())
{
"params" : {
#foreach($type in $allParams.keySet())
#set($params = $allParams.get($type))
"$type" : {
#foreach($paramName in $params.keySet())
"$paramName" : "$util.escapeJavaScript($params.get($paramName))"
#if($foreach.hasNext),#end
#end
}
#if($foreach.hasNext),#end
#end
}
}

实际上,这个映射模板输出负载中的所有请求参数,如下所示:

{
"parameters" : {
"path" : {
"path_name" : "path_value",
...
}
"header" : {
"header_name" : "header_value",
...
}
'querystring" : {
"querystring_name" : "querystring_value",
...
}
}
}

Amazon API网关开发人员指南复制

现在您应该能够为Lambda使用新的代理集成类型来自动获得标准形状的完整请求,而不是配置映射。

看:http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html#api-gateway-set-up-lambda-proxy-integration-on-proxy-resource

从2017年9月开始,您不再需要配置映射来访问请求体。

你所需要做的就是勾选,“使用Lambda代理集成”,在集成请求下,在资源下。

enter image description here

然后,您将能够访问查询参数,路径参数和标题等

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

/用户吗?name =鲍勃

{
"name": "$input.params().querystring.get('name')"
}

获得/ user /鲍勃

{
"name": "$input.params('name')"
}

你可以使用Lambda作为“Lambda代理集成”,引用这个[https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html api-gateway-proxy-integration-lambda-function-python],这个Lambda可用的选项是

对于Nodejs Lambda ”事件。头”、“事件。pathParameters”、“事件。身体”、“event.stageVariables”, 和“event.requestContext”< / p >

For Python Lambda 事件['headers']['parametername']等等

在阅读了其中几个答案后,我在2018年8月使用了几个答案的组合,通过python 3.6的lambda检索查询字符串参数。

首先,我去API网关->我的API ->资源(在左边)->集成请求。在底部,选择映射模板,然后为内容类型输入application/json

接下来,选择Amazon提供的方法请求传递模板,并选择保存和部署API。

然后,lambda event['params']是你访问所有参数的方式。查询字符串:event['params']['querystring']

正如@Jonathan的回答,在集成要求中标记使用Lambda代理集成之后,在你的源代码中,你应该实现如下格式通过传递502网关故障错误。

NodeJS 8.10:

exports.handler = async (event, context, callback) => {
// TODO: You could get path, parameter, headers, body value from this
const { path, queryStringParameters, headers, body } = event;


const response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify({
path,
query: queryStringParameters,
headers,
body: JSON.parse(body)
}),
"isBase64Encoded": false
};


return response;
};
不要忘记在重新运行API之前在API网关部署你的资源。 Response JSON只返回身体中设置的正确值。 因此,你可以从event

获取路径,参数,头,体值

const {path, queryStringParameters, headers, body} = event;

Lambda函数需要JSON输入,因此需要解析查询字符串。解决方案是使用Mapping Template将查询字符串更改为JSON。我用它为c# . net核心,所以预期的输入应该是一个JSON与“queryStringParameters”参数。遵循以下4个步骤来实现这个目标:

  1. 打开API Gateway资源的映射模板,并添加新的application/json content-tyap:

API Gateway mapping template

  1. 复制下面的模板,将查询字符串解析为JSON,并粘贴到映射模板中

    {
    "queryStringParameters": {#foreach($key in $input.params().querystring.keySet())#if($foreach.index > 0),#end"$key":"$input.params().querystring.get($key)"#end}
    }
    
  2. In the API Gateway, call your Lambda function and add the following query string (for the example): param1=111&param2=222&param3=333

  3. The mapping template should create the JSON output below, which is the input for your Lambda function.

    {
    "queryStringParameters": {"param3":"333","param1":"111","param2":"222"}
    }
    
  4. You're done. From this point, your Lambda function's logic can use the query string parameters.
    Good luck!

exports.handler = async (event) => {
let query = event.queryStringParameters;
console.log(`id: ${query.id}`);
const response = {
statusCode: 200,
body: "Hi",
};
return response;
};

我的目标是传递一个类似于:

 protodb?sql=select * from protodb.prototab

到Node.js 12 Lambda函数通过一个URL从API网关。我尝试了其他答案中的一些想法,但真的想以最原生的API网关UI方式做一些事情,所以我想出了这个对我有用的方法(截至2020年12月的API网关UI):

在给定API的API Gateway控制台中,在资源下,选择get方法。然后选择其Integration Request并在页面顶部为lambda函数填写数据。

滚动到底部并打开映射模板部分。如果没有定义模板,则选择“请求正文传递”(推荐)。

点击添加映射模板,创建一个内容类型为application/json的映射模板,然后点击选中标记按钮。

对于该映射模板,在生成模板的下拉列表中选择方法请求传递,它将用AWS传递所有内容的一般方式填充它下面的文本框。

点击保存按钮。

现在当我测试它的时候,我不能让参数通过事件。在Lambda函数下node JS下的sql。事实证明,当API网关将URL sql查询参数发送给Lambda函数时,它对Node.js来说是这样的:

 var insql = event.params.querystring.sql;

所以对我来说,花了一些时间的技巧是使用JSON。通过Stringify来显示完整的事件堆栈,然后通过下面的部分来从查询字符串中提取SQL参数。

基本上,你可以在API网关中使用默认的传递功能,诀窍是当你在Lambda函数中,参数是如何传递的。

对我来说有效的方法是

  1. 转到集成请求
  2. 单击URL查询字符串参数
  3. 单击“添加查询字符串”
  4. 在name字段中放入查询名称,即"name"在这里
  5. 在map From字段中,放入“;method.request.querystring.name”;

Python 3.8 with boto3 v1.16v - 2020年12月

配置路由时,必须配置“API网关”接受路由。否则,除了基本路由之外,其他所有内容都将以{missing auth令牌}或其他内容结束…

一旦你配置API网关接受路由,确保你启用了lambda代理,这样事情就会更好地工作,

要访问路由,

new_route = event['path'] # /{some_url}

访问查询参数

query_param = event['queryStringParameters'][{query_key}]

为了获取查询参数,你可以像这样在queryStringParameters对象中获取它们

const name = event.queryStringParameters.name;

第二个是一个干净的URL。如果你的路径是/user/{name},你可以像这样从pathParameters对象中获取值

const name = event.pathParameters.name;

我的观点是:很多答案都建议激活“使用Lambda代理集成”选项。并从$.event.queryStringParameter$.event.pathParameters中获取参数。但如果你碰巧激活了Access-Control-Allow-Origin(又名CORS),请继续阅读。

在撰写本文时,Lambda代理集成和CORS还不能很好地协同工作。我的方法是禁用Lambda代理集成的复选框,并手动为请求和响应提供一个映射模板,如下所示:

application/json的请求模板:

{
#set($params = $input.params().querystring)
"queryStringParameters" : {
#foreach($param in $params.keySet())
"$param" : "$util.escapeJavaScript($params.get($param))" #if($foreach.hasNext),#end
#end
},
#set($params = $input.params().path)
"pathParameters" : {
#foreach($param in $params.keySet())
"$param" : "$util.escapeJavaScript($params.get($param))" #if($foreach.hasNext),#end
#end
}
}

请注意,我故意将属性命名为queryStringParameterspathParameters,以模拟Lambda代理集成生成的名称。这样,如果有一天我激活Lambda代理集成,我的lambdas将不会中断。

application/json的响应模板:

#set($payload = $util.parseJson($input.json('$')))
#set($context.responseOverride.status = $payload.statusCode)
$payload.body

你如何在你的lambda (python)中读取这些?(假设参数是可选的)

def handler(event, context):
body = event["queryStringParameters"] or {}
result = myfunction(**body)
return {
"statusCode": code,
"headers": {
"content-type": "application/json",
},
"body": result
}