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

How to pass a querystring or route parameter to AWS Lambda from Amazon API Gateway

例如,如果我们想使用

GET /user?name=bob

GET /user/bob

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

我在文档中看到了有关设置 "mapped from" 的内容,但我在 API 网关控制台中找不到该设置。

即使我定义了查询字符串,我也没有看到这些选项。

实现此功能的步骤是:

在 API 网关控制台中...

  1. 转到Resources -> Integration Request
  2. 单击模板下拉列表旁边的加号或编辑图标(我知道这很奇怪,因为模板字段已经打开,这里的按钮看起来是灰色的)
  3. 在内容类型字段中明确键入 application/json,即使它显示默认值(如果您不这样做,它将不会保存并且不会给您错误消息)
  4. 将其放入输入映射中 { "name": "$input.params('name')" }

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

作为尝试回答我自己的一个问题 here 的一部分,我遇到了这个技巧。

在 API 网关映射模板中,使用以下内容为您提供 HTTP 客户端发送的完整查询字符串:

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

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

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

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

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

映射模板实际上是一个 Velocity 模板,您可以在其中使用 ifs、循环,当然还可以在其上打印变量。该模板具有 these variables injected,您可以在其中单独访问查询字符串参数、请求 headers 等。使用以下代码,您可以 re-create 整个查询字符串:

{
    "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 User Guide 了解有关 Velocity 模板语言的更多信息。

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

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

接受的答案对我来说很好,但是扩展 gimenete 的答案,我想要一个通用模板,我可以用它来传递所有 query/path/header 参数(现在只是字符串),然后我想出了以下模板。我将它张贴在这里以防有人发现它有用:

#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、方法、路径和 URL 查询字符串参数。我写了一篇博客 post 更详细地解释了模板: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 网关控制台中包含一个下拉模板。

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

展开"Body Mapping Templates"

输入

application/json

对于 Content-Type(必须明确输入)并单击勾号

一个新的 window 将打开,其中包含文字 "Generate template" 和一个下拉菜单(见图)。

Select

Method Request passthrough

然后点击保存

要访问任何变量,只需使用以下语法(这是 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'])

因此无需明确命名或映射您想要的每个变量。

这里的很多答案都很棒。但我想要一些更简单的东西。 我想要一些可以免费与 "Hello World" 示例一起使用的东西。这意味着我想要一个简单的生成一个与查询字符串匹配的请求主体:

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

我认为最重要的答案在构建真实的东西时会产生更有用的东西,但是要使用 AWS 的模板快速获得 hello world 运行,这非常有效。

查询字符串直接在 lambda

中的 javascript 中解析

对于 GET /user?name=bob

 var name = event.queryStringParameters.name;

虽然这并没有解决 GET user/bob 问题。

以下 parameter-mapping 示例通过 JSON 有效负载

将所有参数(包括路径、查询字符串和 header)传递到集成端点
#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 Gateway Developer Guide

现在您应该能够使用 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 月起,您不再需要配置映射来访问请求 body。

您需要做的就是检查 "Use Lambda Proxy integration",在集成请求下,在资源下。

然后您将能够像这样访问查询参数、路径参数和headers

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

GET /user?name=bob

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

获取/user/bob

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

您可以将 Lambda 用作 "Lambda Proxy Integration" ,参考此 [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 'event.headers', 'event.pathParameters', 'event.body', 'event.stageVariables', 和 'event.requestContext'

对于 Python Lambda 事件['headers']['parametername']等等

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

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

接下来,select Amazon 提供的 Method Request Passthrough 模板 select 保存并部署您的 API。

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

作为@Jonathan 的回答,在 Integration Request 中标记 Use Lambda Proxy integration 后,您应该在源代码中按以下格式实施绕过 502 Bad Gateway 错误。

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;
};

不要忘记在 re-run 您的 API 之前在 API 网关部署您的 资源 。 在body中设置的响应JSON只是return是正确的。 因此,您可以从事件

中获取路径、参数、headers、body 值

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

Lambda 函数需要 JSON 输入,因此需要解析查询字符串。解决方案是使用映射模板将查询字符串更改为 JSON。
我将其用于 C# .NET Core,因此预期输入应该是 JSON 和 "queryStringParameters" 范围。
按照以下 4 个步骤来实现:

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

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

    {
    "queryStringParameters": {#foreach($key in $input.params().querystring.keySet())#if($foreach.index > 0),#end"$key":"$input.params().querystring.get($key)"#end}
    }
    
  2. 在 API 网关中,调用您的 Lambda 函数并添加以下查询字符串(例如):param1=111&param2=222&param3=333

  3. 映射模板应在下面创建 JSON 输出,这是您的 Lambda 函数的 输入

    {
    "queryStringParameters": {"param3":"333","param1":"111","param2":"222"}
    }
    
  4. 大功告成。从这一点来看,您的 Lambda 函数的逻辑可以使用查询字符串参数。
    祝你好运!

参考文档: https://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-lambda.html#api-as-lambda-proxy-expose-get-method-with-path-parameters-to-call-lambda-function

您需要修改映射模板

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

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

在给定 API 的 API 网关控制台上,在资源下,select get 方法。然后 select 它的集成请求并在页面顶部填写 lambda 函数的数据。

滚动到底部并打开映射模板部分。没有定义模板时选择 Request Body Passthrough(推荐)。

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

对于该映射模板,在生成模板的下拉列表中选择 Method Request passthrough,这将使用 AWS 传递所有内容的通用方式填充其下方的文本框。

点击保存按钮。

现在我测试的时候,在lambda函数的node JS下无法获取到参数作为event.sql传过来。事实证明,当 API 网关向 Lambda 函数发送 URL sql 查询参数时,它通过 Node.js 作为:

 var insql = event.params.querystring.sql;

所以我花了一些时间的技巧是使用 JSON.stringify 来显示完整的事件堆栈,然后通过各个部分我的方式来提取 sql 参数来自查询字符串。

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

对我有用的方法是

  1. 转到集成请求
  2. 单击 URL 查询字符串参数
  3. 单击添加查询字符串
  4. 在名称字段中输入查询名称,此处为“名称”
  5. 在“映射自”字段中,输入“method.request.querystring.name”

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

要配置路由,您必须配置 API 网关以接受路由。否则,除了基本路线之外,其他所有内容都将以 {missing auth token} 或其他方式结束...

配置 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;