目录
- 前言
- 正文
- 结尾
前言
在 Golang 中,当异常发生时不管是主动触发 panic 还是由于编码错误导致的 panic,我们都可以使用 recover 进行捕获。当时前提必须定义 defer 语句,且 defer 必须放在 panic 之前定义,另外 recover 只有在 defer 调用的函数中才有效。
正文
今天本文介绍一个编码不规范导致的 panic 异常,下面是错误日志,从日志中我们可以看到程序发生了 panic 异常,并且这个 panic 已经 Gin 框架自带的 Recovery 中间件捕获到了。
报错信息详情:
2021/11/22 09:22:47 [Recovery] 2021/11/22 - 09:22:47 panic recovered: POST /api/transcode/start HTTP/1.1 Host: lozen.test.cn:9903 Connection: close Accept-Encoding: gzip Connection: close Content-Length: 441 Content-Type: application/json User-Agent: GoFrameHTTPClient v1.15.4 interface conversion: interface {} is nil, not map[string]interface {} /usr/local/go/src/runtime/iface.go:261 (0x40ce8e) /root/work/bag/src/server/controllers/transcode.go:626 (0xfdf3a4) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/context.go:165 (0xfa5deb) /root/go/pkg/mod/git.baijiashilian.com/!l!l!l/gloud/gobase@v0.0.0-20211109104743-9df882862f80/utils/trace_middleware.go:18 (0xfa5dca) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/context.go:165 (0xfe79f5) /root/work/bag/src/server/middleware/logger.go:15 (0xfe79b4) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/context.go:165 (0xf55499) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/recovery.go:99 (0xf55480) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/context.go:165 (0xf54573) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/logger.go:241 (0xf54532) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/context.go:165 (0xf4a909) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/gin.go:489 (0xf4a8ef) /root/go/pkg/mod/github.com/gin-gonic/gin@v1.7.3/gin.go:445 (0xf4a3db) /usr/local/go/src/net/http/server.go:2887 (0x725d42) /usr/local/go/src/net/http/server.go:1952 (0x72116c) /usr/local/go/src/runtime/asm_amd64.s:1371 (0x473fc0)
日志的下半段是报错的具体原因,总结下来就是:
interface conversion: interface {} is nil, not map[string]interface {}
根本原因是在服务器端解析参数时,没有对 video 字段进行校验,当 video 字段为空时就会发生上述错误。因为设计之初,云转码服务仅支持视频转码,后来支持了单音频编码功能,比如 mp3、aac。业务端调用原来接口的时候就去掉了 video 字段,如下图所示:
避免上述错误有两种方式,第一种方法,也是最根本的方法,即修改云转码服务代码,不再认为 video 字段是必传项,对 video 字段进行校验。
第二种方法是业务端调用云转码接口传参数时,video 字段可以传空结构体,如下图所示:
注意:空结构体的形式是大括号 {}
,不是 ""
,也不是 nil
。
结尾
最后,总结一下 Golang 在处理异常捕获时的一些注意事项,首先,defer 语句需要提前定义,否则当 panic 发生时,recover 是无法捕获到 panic 异常的。其次,recover 处理异常后,逻辑并不会恢复到 panic 的实际发生位置,而是执行 defer 之后的语句段。最后,多个 defer 语句会形成 defer 栈,后定义的 defer 语句会先执行。
作者简介:大家好,我是 liuzhen007,是一位音视频技术爱好者,同时也是CSDN博客专家、华为云享专家、InfoQ 签约作者,欢迎关注我分享更多干货!