Discord无法验证Golang AWS Lambda交互端点问题排查
问题描述
我想要搭建一个通过HTTP端点交互的Discord机器人,采用Golang编写的AWS Lambda并通过AWS API Gateway暴露,但在设置“INTERACTIONS ENDPOINT URL”时,Discord提示端点无法验证。日志显示第一个请求成功通过头部验证并响应了PING,但第二个请求出现授权错误。相同代码在另一个项目中可正常运行。
核心处理函数
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { rawBody := request.Body fmt.Println("start") // validate nacl header err := validator.verifyRequest( request.Headers["x-signature-ed25519"], request.Headers["x-signature-timestamp"], request.Body, ) if err != nil { fmt.Println("StatusUnauthorized") return formatUnauthorizedResponse() } discordRequest := DiscordRequestDto{} err = json.Unmarshal([]byte(rawBody), &discordRequest) // validate ping fmt.Println("test ping") if validator.IsPing(discordRequest.Type) { fmt.Println("is ping !") return formatPingResponse() } return formatResponse("ok") }
日志详情
START RequestId: 590104c1-4353-4153-8708-614c6afcdbbc Version: $LATEST start test ping is ping ! ping END RequestId: 590104c1-4353-4153-8708-614c6afcdbbc REPORT RequestId: 590104c1-4353-4153-8708-614c6afcdbbc Duration: 36.13 ms Billed Duration: 37 ms Memory Size: 128 MB Max Memory Used: 29 MB Init Duration: 97.97 ms START RequestId: b9e94769-0b0d-421b-91c3-72748f333567 Version: $LATEST start StatusUnauthorized END RequestId: b9e94769-0b0d-421b-91c3-72748f333567 REPORT RequestId: b9e94769-0b0d-421b-91c3-72748f333567 Duration: 18.34 ms Billed Duration: 19 ms Memory Size: 128 MB Max Memory Used: 30 MB
完整代码
代码位于GitHub仓库DavidVergison/discord-bot-error中
解决方案
问题出在未处理AWS Lambda请求中的IsBase64Encoded标志。AWS API Gateway会根据请求体类型,将部分请求的body以base64编码形式传递给Lambda:
- 第一个PING请求的body内容简单,未被base64编码,直接使用
request.Body验证通过; - 第二个请求的body被API Gateway编码为base64,你直接用编码后的字符串参与签名验证,导致和Discord生成签名时的原始body不匹配,验证失败。
修改handler函数,先判断IsBase64Encoded并解码body:
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { fmt.Println("start") // 处理base64编码的body var rawBody string if request.IsBase64Encoded { decodedBytes, err := base64.StdEncoding.DecodeString(request.Body) if err != nil { fmt.Println("Failed to decode base64 body") return formatUnauthorizedResponse() } rawBody = string(decodedBytes) } else { rawBody = request.Body } // validate nacl header err := validator.verifyRequest( request.Headers["x-signature-ed25519"], request.Headers["x-signature-timestamp"], rawBody, // 使用解码后的原始body ) if err != nil { fmt.Println("StatusUnauthorized") return formatUnauthorizedResponse() } discordRequest := DiscordRequestDto{} err = json.Unmarshal([]byte(rawBody), &discordRequest) if err != nil { fmt.Println("Failed to unmarshal request") return formatUnauthorizedResponse() } // validate ping fmt.Println("test ping") if validator.IsPing(discordRequest.Type) { fmt.Println("is ping !") return formatPingResponse() } return formatResponse("ok") }
同时需确保API Gateway的集成设置中,Content Handling配置为Passthrough,避免API Gateway修改原始请求体内容。
内容的提问来源于stack exchange,提问作者David Vergison
相关产品推荐
相关产品推荐

