使用 http 端点访问 lambda 中的 HTTP 请求(标头、查询字符串、cookie、正文)对象

Posted

技术标签:

【中文标题】使用 http 端点访问 lambda 中的 HTTP 请求(标头、查询字符串、cookie、正文)对象【英文标题】:Access HTTP request (headers, query string, cookies, body) object in lambda with http endpoint 【发布时间】:2015-10-29 08:54:54 【问题描述】:

我正在尝试查看如何从 lambda 代码中访问请求标头和正文值。如果请求正文是 JSON 格式,它似乎会自动被解析并在事件对象中可用。

如何访问 Lambda 内任何类型的传入“Content-Type”请求的完整查询字符串、请求正文、请求标头 (cookie)?


下面的编辑是我收集的信息,以帮助解决可能相关或不相关的问题。如果您愿意,请忽略它们。


编辑:

我查看了关于 SE here 和 here 的现有问题。 根据这个thread,使用$input.json('$') 应该可以解决问题。我猜上面这些链接的答案已经过时了,因为默认情况下 API 网关似乎可以识别请求中的 JSON,如果是这样,它可以在 event 对象中使用,而无需配置任何映射模板。

按照建议设置映射对我不起作用。不包含请求头信息。

以下是有关如何配置的屏幕截图。


“headers”键返回一个空白值。使用$input.params('$')"$input.params('$')" 会出错。


编辑 2

尝试在方法请求中定义标头。仍然没有在 lambda 中获取 User-Agent 值。


编辑 3

我在 API 网关使用了以下模板映射


    "request": $input.json('$'),
    "headers": "$input.params()"

以及下面的 lambda 代码

context.succeed("event.key32:"+JSON.stringify(event, null, 2) );

API 网关生成的响应显示了这一点

查看响应中的“标头”值,AWS-SDK/API 网关/cloudfront 似乎剥离了从 HTTP 客户端接收到的所有标头?这是 $input.params().header 返回的 JSON 的全文

header=CloudFront-Forwarded-Proto=https, CloudFront-Is-Desktop-Viewer=true, CloudFront-Is-Mobile-Viewer=false, CloudFront-Is-SmartTV-Viewer=false, CloudFront-Is-Tablet-Viewer=false, Content-Type=application/json, Via=1.1 5d53b9570d94ce920abbd471.cloudfront.net (CloudFront), 1.1 95eea7baa7ec95c9a41eca9e3ab7.cloudfront.net (CloudFront), X-Amz-Cf-Id=GBqmObLRy6Iem9bJbVPrrW1K3YoWRDyAaMpv-UkshfCsHAA==, X-Forwarded-For=172.35.96.199, 51.139.183.101, X-Forwarded-Port=443, X-Forwarded-Proto=https

标题中没有 User-Agent 字符串,尽管如上面的屏幕截图所示,它是由 REST 客户端发送的。 有趣的是,整个查询字符串都可用。不确定这是否是预期的访问方式。

【问题讨论】:

你能简化一下这个问题吗?现在真的很臃肿。 @napalm,我已经突出显示了问题部分。请忽略编辑。总结一下这个问题:我如何访问 Lambda 内任何类型的传入“Content-Type”请求的完整查询字符串、请求正文、请求标头(cookie)? 【参考方案1】:

可以使用$input.params('header-name')访问请求头

令人惊讶的是,上面的代码无法访问 User-Agent 标头。你需要跳过the下面的箍来找回它:

$context.identity.userAgent

应该可以使用以下代码访问请求正文/有效负载。更多参考here、here和here:


   "reqbody": "$input.path('$')"

目前尚不清楚请求正文是否应为 JSON。需要注意的是,根据this post,请求被视为UTF-8。


目前好像有两个bugs:

    “User-Agent”标头丢失/被 Amazon API 剥离。

    当标头值包含双引号 (") 时,不会执行 lambda 函数。(我在 cloudwatch 日志中没有看到此类请求的日志条目)。相反,http响应正文包含以下内容:

    
       "Type": "User",
       "message": "Could not parse request body into json."
    
    

在 Amazon API 中失败的示例请求

我认为这需要更正才能实现 ETag 缓存机制。

参考资料:

Etag 应该用双引号括起来。浏览器应该通过 If-None-Match 标头发回这个确切的值,这就是 Amazon API 中断的地方。

Syntax for ETag?

HTTP: max length of etag

http://gsnedders.com/http-entity-tags-confusion

【讨论】:

【参考方案2】:

似乎如果没有发送“Content-Type”,AWS API Gateway 会将其默认为“application/json”: https://forums.aws.amazon.com/thread.jspa?threadID=215471

所以只需为“application/json”定义映射模板。

【讨论】:

【参考方案3】:

您必须在模板映射中获取您需要的信息并将它们发送回您的 Lambda 函数,这是我用来向 Lambda 函数发送信息的模板之一:


   "params" : "$input.params()",
   "content-type-value" : "$input.params().header.get('Content-Type')",
   "body" : "$input.json('$')",
   "request-id": "$context.requestId",
   "method": "$context.httpMethod",
   "resource": "$context.resourcePath",
   "id": "$input.params('id')" //This is a path parameter in my case

您也可以这样做,或者您可以访问params.path.id(在我的情况下也是如此)。这是文档中的link。

干杯,

【讨论】:

【参考方案4】:

我更新了在回答一个引用问题时使用的映射模板以包含 userAgent 属性。


  "method": "$context.httpMethod",
  "body": $input.json('$'),
  "userAgent": "$context.identity.userAgent",
  "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
    

此处提供了模板的详细说明: http://kennbrodhagen.net/2015/12/06/how-to-create-a-request-object-for-your-lambda-event-from-api-gateway/

【讨论】:

以上是关于使用 http 端点访问 lambda 中的 HTTP 请求(标头、查询字符串、cookie、正文)对象的主要内容,如果未能解决你的问题,请参考以下文章

如何从 lambda 访问 cognito 联合身份中的身份数据集

是否可以使用 AWS API 为 Lambda 函数设置 AWS API Gateway 端点?

AWS Lambda 函数 API 端点 - 403 和 415 错误

API Gateway Lambda 端点代理与非代理集成

Serverless graphql 拆分成微服务

如何在自定义授权方 AWS lambda 函数中访问 http 标头