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

250 天前
 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 是哪种错误? 这么粗暴的吗?

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

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

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

你应该定义一个 ErrDBConnection. 然后在 http 服务 errors.Is(err, repository.ErrDBConnection).
kk2syc
250 天前
可以直接 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
250 天前
java 有个地方处理这个特殊异常,go 中间件不就是这个特殊的地方吗

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

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

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

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

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

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

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

© 2021 V2EX