go 没有异常 怎么判断逻辑以外的错误 全局的处理

3 天前
 dzdh

比如数据库服务吧。

程序启动,先连 db 。连成功。启动 web 服务。然后 setup 路由啥的一堆。

好,服务启动成功了。

现在接受 http 请求,此时数据库崩了。

gorm 返回了 err 。比如代码如下

// userRepository.go
func GetUser(uid int64) (*User, error) {
    user:=new(User)
    if err :=db.model(user).Find(user).err; err != nil {
        return nil,err
    } else { return user, nil }
}

按照 java/php 这种的逻辑。我可以抛出个异常。然后有个地方是处理这个特殊的异常。返回 500,db no connection 。

go 里边咋做呢?现在数据库崩了以后,被业务中间件拦截到了 返回 401 unauthorized 。

repository 由 http 服务调用。我要直接 panic 吗 0.0 http 的中间件 recover 住判断 err 是哪种错误? 这么粗暴的吗?

3373 次点击
所在节点    Go 编程语言
40 条回复
voidmnwzp
3 天前
跟 java 一样向上抛啊
sduoduo233
3 天前
我一般是返回 500 ,然后记录一下错误
u,err:=GetUser(1)
if err!=nil {
w.WriteHeader(500)
log.Println(err)
return
}
dzdh
3 天前
@voidmnwzp @sduoduo233

其实返回个 401 也没毛病。就是觉得怪怪的
laikick
3 天前
Panic + Recover + 自定义错误类型 就可以实现类似 Java 的操作 不过也仅仅是类似. 但是,这不是 go 推荐的.

别把 Java 的习惯带入 go 里面. 这两个语言的思想差别很大的.

你应该定义一个 ErrDBConnection. 然后在 http 服务 errors.Is(err, repository.ErrDBConnection).
kk2syc
3 天前
可以直接 panic ,可以用中间件捕获。不一定比全局优雅,但是也是不错的,业务上我都这样。
----

func ExceptionMiddleware(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
c.JSON(500, gin.H{"msg": "ERROR"})
c.Abort()
}
}()
c.Next()
}
kingcanfish
3 天前
java 有个地方处理这个特殊异常,go 中间件不就是这个特殊的地方吗

我一般是自己定义一些 error 比如 db error, logic errr, client err, 在最先抛出 error 的地方包一层, 然后网上传 最终中间根据不同的 error 返回错误码 ,比如你这个例子, 发现 db 包 error 了 我就包一层 自己的 db error ,往上抛, 中间件捕获
dzdh
3 天前
@kingcanfish 抛就是 panic 呗?
realpg
3 天前
还是不建议这么跨舒适区干活
玩惯了 exception 那一套 改 go 推荐这一套 可能一年都改不过来
不如再找个 java 工作
kingcanfish
3 天前
@dzdh #7 error
lasuar
3 天前
改不过来习惯 ,不建议写 go ,难受自个。编程范式都不一样了。
zoharSoul
3 天前
@realpg #8 人家是 php 干嘛找 java 的
php 都是转 go 的
afxcn
3 天前
repository 返回正确的错误类型就好了。
Blackbelly
3 天前
直接 panic

因为数据库崩了属于 unrecoverable 的错误。这时候当成 err 向上抛没有意义,上一层也无法处理,只能层层往上抛。
而且,你的接口语义是 GetUser ,本身就不应该返回一个接口语义之外的错误。
按照接口语义,应该是返回一个 user ,或者是 NotFoundErr ,除此之外的错误都不应该返回。
chen11
3 天前
我上周才遇见个 bug ,go 程序直接崩溃,log 没打出来,找不到 bug 在哪里。习惯了 java ,来写 go 就难受
zsj950618
3 天前
> 被业务中间件拦截到了 返回 401 unauthorized

那是这个中间件垃圾,都不看错误类型就一股脑返回 401 。
chevalier
3 天前
从功能上来说
Go 的 error 相当于 Java 的异常
Go 的 panic 相当于 Java 的 Error
changz
3 天前
用 protobuf 定义错误码,一层一层往上抛
wangritian
3 天前
所有语言的最佳实践,都可以在流行框架内找到,推荐到 goframe 看看
go 一般是自己设计一个符合 error 接口(包含 Error 方法)的带 code 和 msg 的自定义 error
通过 recover 全局拦截异常,如果是底层报错(数据库连接失败等业务层无须接收),直接 panic
如果是业务异常(用户名重复),return 自定义 error
guanzhangzhang
3 天前
返回 error ,上层处理和家 warp 信息,最后到你接口层面你可以返回 500
leonshaw
3 天前
我一般只有断言失败才用 panic ,其它情况都是返回 error ,视情况包装一层。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1100894

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX