AWS API Gateway VTL合并Lambda Authorizer的principalId至Event Bridge负载报错
解决API Gateway请求模板中EventBridge Detail格式错误问题
问题描述
需要将Lambda Authorizer返回的principalId合并到发送给EventBridge的负载中,当前通过转换为Map并重建JSON对象的方式实现,但生成的JSON键名无引号,导致EventBridge返回MalformedDetail错误。API Gateway的Velocity模板不支持AppSync的$util.toJson()方法,需寻找替代方案。
相关CDK代码
const eventsAPI = new RestApi(this, 'eventsAPI', apigwOps); const LambdaAuth0Authorizer = new LambdaAuth0Authorizer(this, 'LambdaAuth0Authorizer', { env: { auth0Audience: '', auth0Domain: '', }, }); const eventTypeResource = eventsAPI.root.addResource('event'); const options: IntegrationOptions = { credentialsRole: apigwRole, passthroughBehavior: PassthroughBehavior.NEVER, requestParameters: { 'integration.request.header.X-Amz-Target': "'AWSEvents.PutEvents'", 'integration.request.header.Content-Type': "'application/x-amz-json-1.1'", }, requestTemplates: { 'application/json': ` #set ( $map = $util.parseJson($input.body) ) #set ( $j = { "eventType": "$map['eventType']", "action": "$map['action']", "subject": "$map['subject']", "eventTime": $map['eventTime'], "actor": "$context.authorizer.principalId" } ) {"Entries": [ { "Source": "com.xyz", "Detail": "$util.escapeJavascript($j)", "Resources": [], "DetailType": "event", "EventBusName": "${eventBus.eventBusName}" } ] } `, }, integrationResponses: [ { statusCode: '200', responseTemplates: { 'application/json': '', }, }, ], }; eventTypeResource.addMethod('POST', new Integration({ type: IntegrationType.AWS, uri: `arn:aws:apigateway:${env.region}:events:path//`, integrationHttpMethod: 'POST', options: options, }), { authorizer: LambdaAuth0Authorizer.authorizer, methodResponses: [{ statusCode: '200' }], requestModels: { 'application/json': getEventModel(this, eventsAPI) }, requestValidator: new RequestValidator(this, 'eventValidator', { restApi: eventsAPI, validateRequestBody: true, }), });
生成的错误请求内容
{"Entries": [ { "Source": "com.uproarapi", "Detail": "{eventType=FOLLOW, action=CREATE, subject=USER_777POIUY, eventTime=51644444444, actor=}", "Resources": [], "DetailType": "UpRoarEvent", "EventBusName": "UpRoarEventBus" } ] }
返回的错误信息
{"Entries":[{"ErrorCode":"MalformedDetail","ErrorMessage":"Detail is malformed."}],"FailedEntryCount":1}
解决方案
问题根源在于Velocity模板中直接引用Map对象$j时,会输出Java对象的默认字符串形式(键名无引号),而非标准JSON。我们可以通过手动构建符合JSON规范的Detail字符串来解决:
修改请求模板中的application/json部分为以下内容:
#set ( $map = $util.parseJson($input.body) ) { "Entries": [ { "Source": "com.xyz", "Detail": "{\"eventType\":\"$util.escapeJavaScript($map.eventType)\",\"action\":\"$util.escapeJavaScript($map.action)\",\"subject\":\"$util.escapeJavaScript($map.subject)\",\"eventTime\":$map.eventTime,\"actor\":\"$util.escapeJavaScript($context.authorizer.principalId)\"}", "Resources": [], "DetailType": "event", "EventBusName": "${eventBus.eventBusName}" } ] }
关键修改说明
- 直接拼接
Detail的JSON字符串,所有键名用双引号包裹,符合JSON格式要求 - 对字符串类型的字段(
eventType、action等)使用$util.escapeJavaScript()处理,避免特殊字符(如引号、反斜杠)破坏JSON结构 - 数值类型的
eventTime保持无引号,与原输入格式一致
修改后生成的Detail会是标准JSON字符串,示例如下:
"Detail": "{\"eventType\":\"FOLLOW\",\"action\":\"CREATE\",\"subject\":\"USER_777POIUY\",\"eventTime\":51644444444,\"actor\":\"auth0-user-id\"}"
这样EventBridge就能正确解析Detail内容,不会再抛出格式错误。
内容的提问来源于stack exchange,提问作者Esteban Rincon
相关产品推荐
相关产品推荐

