如何从Amazon API Gateway将查询字符串或路由参数传递给AWS Lambda

502
例如,如果我们想要使用 GET /user?name=bobGET /user/bob 如何将这两个示例作为参数传递给Lambda函数?
我在文档中看到了设置“mapped from”的内容,但我无法在API网关控制台中找到该设置。
以下是用于表示路径参数和查询字符串参数的变量:
- method.request.path.parameter-name 表示在 Method Request 页面中定义的名为 parameter-name 的路径参数。 - method.request.querystring.parameter-name 表示在 Method Request 页面中定义的名为 parameter-name 的查询字符串参数。
尽管我已经定义了一个查询字符串,但我并没有看到这两个选项之一。
23个回答

518

从2017年9月起,您无需配置映射即可访问请求主体。

您所需做的就是在资源下方的Integration Request中勾选"Use Lambda Proxy integration"。

输入图像描述

然后,您就可以像这样访问查询参数、路径参数和标头。

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

43
这是一个很好的提示。但要记住,开启Lambda代理集成可能会导致“异常的Lambda代理响应”错误。以下是解决方法:https://dev59.com/31cP5IYBdhLWcg3w39o- - AaronBaker
“Integration Request” 位于哪里?编辑:算了,下面的评论说在API Gateway控制台中。 - Colin D
我认为SO应该增加一个选项,让用户可以为这样有帮助的答案支付给作者报酬!谢谢伙计!你帮我节省了好几个小时。你知道在文档中提到了这个吗? - undefined

245
获取操作步骤如下:

进入API网关控制台...

  1. 转到资源->整合请求
  2. 单击模板下拉列表旁边的加号或编辑图标 (很奇怪,因为模板字段已经打开,这里的按钮看起来是灰色的)
  3. 即使显示默认值,也要在内容类型字段中明确输入 application/json (如果不这样做,它将无法保存,并且不会给出错误消息)
  4. 将以下内容放入输入映射中:{ "name": "$input.params('name')" }
  5. 选中模板下拉列表旁边的复选框(我想这最终保存了它)

13
你是否曾经尝试过在 URL 参数中发送像 /user/bob 这样的 URL,其中路由为 /user/{username}?我已经尝试了各种排列组合,但一直无法解决这个问题。 - Lucas

165

我使用了这个映射模板,将 Body、 Headers、 Method、 Path 和 URL 查询字符串参数提供给 Lambda 事件。我撰写了一篇关于该模板更详细说明的博客文章: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
  }  
}

1
太棒了!我曾经为如何以通用的方式传递参数给我的处理器而苦恼。这是最好的答案。 - Venkat D.
我已经尝试了这个,但是还没有得到任何结果。它显示为未定义。我们应该如何在URL中发送参数?我们是否需要像普通的GET URL场景中一样在URL中指定变量名?请帮我解决这个问题。 - Parthapratim Neog
10
没关系,我得到了结果。问题是,我添加了映射并保存了它,但没有再次“部署”API。一旦我用新映射部署了API,它就可以正常工作了。非常感谢。 - Parthapratim Neog
@shashu10 请看我的回答。 - matsev
1
我无法用言语形容你的博客有多有用。我最初找到了“从AWS API网关返回HTML”这篇文章并按照其中的步骤进行操作,因为那正是我所需的。现在我需要向函数传递一些参数,并基于这些参数修改HTML - 再次感谢你提供的详细指南!其他所有教程似乎都没有解决问题。 - user3685427
这是最好的答案。pathParams 对我没用,但我用 "uri": "$context.path" 得到了它。我没有使用代理或 CORS。 - copycat

47

现在,AWS的API Gateway控制台中已包括下拉式模板。

对于您的API,请单击资源名称...然后选择GET

展开“Body Mapping Templates”

在Content-Type中键入

application/json

(必须显式输入),然后单击确认

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

选择

Method Request passthrough

enter image description here

然后单击保存

要访问任何变量,只需使用以下语法(这是Python代码):

例如,URL:

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'])
因此,没有必要明确命名或映射您想要的每个变量。

如何访问路径参数? - Saurabh Chandra Patel

30

为了将参数传递给您的Lambda函数,您需要在API网关请求和Lambda函数之间创建映射。该映射在所选API网关资源的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('$')
}

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

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

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

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

10
这是最佳解决方案。请记得执行 操作>部署API,然后(我曾因忘记这一步浪费了时间...)。相关的lambda arn将在部署后立即进行更改。您可以在“阶段>#阶段(如:prod)>部署历史记录”中进行检查。 - loretoparisi

26

接受的答案对我很有效,但是在扩展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
}

1
太棒了,我想要能够同时用于POST(带有JSON主体)请求和GET查询字符串的相同函数。完美运作。谢谢! - Matt Fletcher
@benv 这是完整的模板吗? - nxmohamad

20

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

在API Gateway映射模板中,使用以下内容可以使你获得HTTP客户端发送的完整查询字符串:

{
    "querystring": "$input.params().querystring"
}
优点在于您不需要将查询字符串中的键限制为一组预定义的映射键。现在,如果这符合您的处理方式,您可以接受查询字符串中的任何键值对。 注意:根据此文档,仅列出了$input.params(x)作为可在VTL模板中使用的变量。内部可能会更改,querystring可能不再可用。

1
截至2017年5月,这仍然有效,但它返回API Gateway为您创建的JS对象,而不是实际的查询字符串。对我来说很烦人,因为我正在尝试解析查询字符串以将重复的参数转换为数组。 - Tom Saleeba
$input.params().querystring 不会返回一个 JSON 对象,它会生成类似这样的内容:{"querystring" : {param1=value1, param2=value2}}。 - Leopoldo Varela

15

在Lambda中,解析JavaScript中的查询字符串非常简单。

对于GET /user?name=bob

 var name = event.queryStringParameters.name;

但是这并没有解决GET user/bob的问题。


3
它的 event.queryStringParameters.name - Neo
1
我必须执行 event.queryStringParameters.name - Anders Kitson

15

2
我不确定为什么,但代理集成通常对我没用。我不得不从我创建的最新API中删除它。 - Gustavo Straube
同样的问题,我在使用API Gateway时遇到了CORS问题。按照AWS文档的步骤,我无法使CORS正常工作。然而,我找到了一篇2015年中后期的旧Medium文章,其中介绍了手动设置CORS的方法,并且这种方法有效。 - Stephen Tetreault

14

GET /user?name=bob

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

获取 /user/bob

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接