如何在AWS API Gateway VLT映射模板中正确转义JSON?
问题描述
我正在通过AWS API Gateway使用Velocity模板语言(VTL)转换事件体后向EventBridge发布事件,遇到了MalformedDetail错误。
原始事件体
{ "ordersDelivered": [ { "orderId": "a0874e2c-4ad3-4fda-8145-18cc51616ecd", "address": { "line2": "10 Broad Road", "city": "Altrincham", "zipCode": "WA15 7PC", "state": "Cheshire", "country": "United Kingdom" } } ] }
初始VTL模板
#set($context.requestOverride.header.X-Amz-Target = "AWSEvents.PutEvents") #set($context.requestOverride.header.Content-Type = "application/x-amz-json-1.1") #set($inputRoot = $input.path('$')) { "Entries": [ #foreach($elem in $inputRoot.ordersDelivered) { "Resources" : ["$context.authorizer.clientId"], "Detail" : "$util.escapeJavaScript($elem)", "DetailType" : "OrderDelivered", "EventBusName" : "hk-playground-more-sole", "Source" : "delivery" }#if($foreach.hasNext),#end #end ] }
错误日志
调用后收到EventBridge返回的格式错误:
Endpoint request body after transformations: { "Entries": [ { "Resources" : [""], "Detail" : "{orderId=a0874e2c-4ad3-4fda-8145-18cc51616ecd, address={line2=10 Broad Road, city=Altrincham, zipCode=WA15 7PC, state=Cheshire, country=United Kingdom}}", "DetailType" : "OrderDelivered", "EventBusName" : "hk-playground-more-sole", "Source" : "delivery" } ] } Sending request to https://events.{aws-region}.amazonaws.com/?Action=PutEvents Received response. Status: 200, Integration latency: 32 ms Endpoint response headers: {x-amzn-RequestId=6cd086bf-5147-4418-9498-b467ed2b6b58, Content-Type=application/x-amz-json-1.1, Content-Length=104, Date=Thu, 15 Sep 2022 10:17:44 GMT} Endpoint response body before transformations: {"Entries":[{"ErrorCode":"MalformedDetail","ErrorMessage":"Detail is malformed."}],"FailedEntryCount":1} Method response body after transformations: {"Entries":[{"ErrorCode":"MalformedDetail","ErrorMessage":"Detail is malformed."}],"FailedEntryCount":1}
我尝试过用$util.toJson($elem)替代$util.escapeJavaScript($elem),但Detail变成空字符串并返回400错误;也尝试直接用JSONPath读取ordersDelivered,但错误依旧。
解决方案
问题出在$elem是Velocity内部对象,直接调用$util.escapeJavaScript会输出对象的toString格式(非标准JSON),而$util.toJson对这种对象处理异常导致空值。正确的做法是先通过JSONPath重新获取$elem的标准JSON字符串,再转义:
修改后的VTL模板:
#set($context.requestOverride.header.X-Amz-Target = "AWSEvents.PutEvents") #set($context.requestOverride.header.Content-Type = "application/x-amz-json-1.1") #set($inputRoot = $input.path('$')) { "Entries": [ #foreach($elem in $inputRoot.ordersDelivered) #set($elemJson = $input.path('$.ordersDelivered[' + $foreach.index + ']')) { "Resources" : ["$context.authorizer.clientId"], "Detail" : "$util.escapeJavaScript($elemJson)", "DetailType" : "OrderDelivered", "EventBusName" : "hk-playground-more-sole", "Source" : "delivery" }#if($foreach.hasNext),#end #end ] }
解释
- 用
$foreach.index获取当前循环的索引,通过JSONPath$.ordersDelivered[$index]直接从原始输入中提取该条目的标准JSON字符串。 - 再对这个JSON字符串执行
$util.escapeJavaScript,确保双引号等特殊字符被正确转义,符合EventBridge要求的Detail字段格式(必须是转义后的JSON字符串)。
另外,如果你不需要Resources字段里的clientId,可以留空或者移除该字段,避免出现空数组的情况。
内容的提问来源于stack exchange,提问作者Hemant
相关产品推荐
相关产品推荐

