使用 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 端点?