使用VTL为AWS API Gateway编写自定义错误响应映射模板报内部服务错误
AWS API Gateway VTL映射模板返回500错误排查
问题描述
为AWS API Gateway的集成响应编写VTL映射模板,期望返回自定义格式的错误输出。
第一版模板代码如下:
{ "gw_code":"$gw_code", "er_code":"$er_code", "code":"$gw_code" + "-" + "$er_code", "developerMessage":"$developerMessage" "message":"$message" "gw_msg":"$code $developerMessage" } #set ($er_num = "200") #set ($er_msg = "ACCESS_DENIED") #if($code == "403-001" && $developerMessage == "Unauthorized") // Ignore #else { "code" : "403-001", "developerMessage" : "Unauthorized." } #end
部署后访问接口返回内部服务器错误,响应内容为:
{"message": "Internal server error"}
参考VTL语法规则精简修改后得到第二版模板:
#set($messageOverride = "foo") { #if($status == "403-001" && $developerMessage = "Unauthorized") // Ignore #else #if($inputRoot.toString().contains("error")) "code" : "403-001", "developerMessage" : "Unauthorized." #end #end #end }
修改后500错误仍然存在,无法定位问题点。
错误原因
两版模板同时存在VTL语法错误、输出JSON结构非法两类问题,任意一个问题都会触发API Gateway的模板解析失败,直接返回500响应:
- 第一版模板问题:
- JSON语法错误:
"developerMessage":"$developerMessage"、"message":"$message"两个键值对末尾缺少分隔逗号;gw_msg字段直接换行写值,生成非法JSON格式 - VTL语法错误:不支持在JSON值位置直接用
+做字符串拼接,拼接逻辑必须放在#set指令中完成;使用//写注释,VTL会将其识别为普通文本输出,破坏JSON结构 - 输出结构错误:第一个JSON对象闭合后,条件分支又输出第二个独立JSON对象,最终响应是两段拼接的无效内容
- JSON语法错误:
- 第二版模板问题:
- VTL语法错误:条件判断中用单等号
=做相等比较,VTL中相等判断必须使用双等号==;直接调用未定义的$inputRoot变量方法,触发解析异常;#if块闭合位置错误,多余的#end导致VTL引擎解析失败 - 同样存在
//注释被输出破坏JSON结构的问题
- VTL语法错误:条件判断中用单等号
注意:API Gateway对VTL映射模板的输出校验非常严格,最终输出必须是完全合法的JSON结构,任何多余字符、格式错误都会直接返回500。VTL的单行注释必须用
##开头,多行注释需要用#* ... *#包裹。
修复参考模板
## 提前拼接错误码,避免在JSON结构中写运算逻辑 #set($respCode = "${gw_code}-${er_code}") ## 提前处理分支逻辑,确定最终返回字段值 #if($respCode == "403-001" && $developerMessage == "Unauthorized") #set($finalCode = $respCode) #set($finalDevMsg = $developerMessage) #else #set($finalCode = "403-001") #set($finalDevMsg = "Unauthorized.") #end ## 最后输出唯一的合法JSON结构 { "gw_code": "$gw_code", "er_code": "$er_code", "code": "$finalCode", "developerMessage": "$finalDevMsg", "message": "$message", "gw_msg": "${finalCode} ${finalDevMsg}" }
如果需要使用$inputRoot读取集成响应的内容,必须在使用前先赋值:#set($inputRoot = $input.path('$')),不能直接调用未声明的变量。
内容的提问来源于stack exchange,提问作者JSol69
相关产品推荐
相关产品推荐

