Closed islishude closed 4 years ago
Go 网络开发中的常用的应用层协议库都是基于 net 标准库开发的,比如 gorilla/websocket 和 go-grpc,还有最常用的 http 库。
当请求一个不存在的 host 时会返回一个错误,如下所示
$ cat main.go package main import ( "fmt" "net/http" ) func main() { if _, err := http.Get("http://unknownhost.example"); err != nil { fmt.Println(err) } } $ go run main.go Get "http://unknownhost.example": dial tcp: lookup unknownhost.example: no such host
这个错误本质其实是 *net.DNSError,在 Go 早期开发中,会经常使用接口断言匹配错误。
*net.DNSError
比如这样 if v, ok := err.(*net.DNSError);ok {} 的形式。
if v, ok := err.(*net.DNSError);ok {}
如果这样使用的话,实际上不会匹配断言匹配到,在 debug 模式可以看到最后返回其实是 *url.Error,然后内部才实际包裹了 (*net.DNSError) 错误,并实现 Unwarp() error 方法。
*url.Error
(*net.DNSError)
Unwarp() error
// url.Error type Error struct { Op string URL string Err error // 上述例子中,这里包裹了 *net.DNSError 错误 }
在 go 1.13 之后,errors.As 可以进行解包错误,那么我们就可以直接使用下面方式即可:
errors.As
package main import ( "errors" "fmt" "net" "net/http" ) func main() { if _, err := http.Get("http://unknownhost.example"); err != nil { if v := (*net.DNSError)(nil); errors.As(err, &v) { fmt.Println("can't found", v.Name) } } }
除了 *net.DNSError 之外,还有下面内置错误结构体:
上面错误除了实现了 Error() 接口,还实现了 Timeout() bool 和 Temporary() bool 接口,也就是实现了 net.Error 接口
Timeout() bool
Temporary() bool
net.Error
// net.Error type Error interface { error Timeout() bool // Is the error a timeout? Temporary() bool // Is the error temporary? }
同时也实现了 Unwarp() 接口,用于错误解包。那么我们就可以区分请求的错误是网络错误,还是服务器错误。
Unwarp()
比如在 jsonrpc 协议中定义了 Error 结构体,使用下面方式进行判断
type JsonError struct { Code int `json:"code"` Msg string `json:"message"` Data interface{} `json:"data"` } func (e *JsonError) Error() string { return e.Msg } func main() { if _, err := jsonrpc.Call("http://jsonrpc.example"); err != nil { if v := (net.Error)(nil); errors.As(err, &v) { fmt.Println("is timeout?", v.Timeout()) return } if v := (*Error)(nil); errors.As(err, &v) { fmt.Println("jsonrpc error: Code:", v.Code, "Msg", v.Msg) } } }
如果按照以前的方式不断通过接口断言的解包错误的形式,那么代码很快会形成类似”回调地狱“的模样。
所以,在实际应用层开发上,直接可以使用 fmt.Errorf("Stack: %w",err) 包装错误,最后调用方最后使用 errros.As 或 errros.Is 解包按需处理错误。
fmt.Errorf("Stack: %w",err)
errros.As
errros.Is
Go 网络开发中的常用的应用层协议库都是基于 net 标准库开发的,比如 gorilla/websocket 和 go-grpc,还有最常用的 http 库。
当请求一个不存在的 host 时会返回一个错误,如下所示
这个错误本质其实是
*net.DNSError
,在 Go 早期开发中,会经常使用接口断言匹配错误。比如这样
if v, ok := err.(*net.DNSError);ok {}
的形式。如果这样使用的话,实际上不会匹配断言匹配到,在 debug 模式可以看到最后返回其实是
*url.Error
,然后内部才实际包裹了(*net.DNSError)
错误,并实现Unwarp() error
方法。在 go 1.13 之后,
errors.As
可以进行解包错误,那么我们就可以直接使用下面方式即可:除了 *net.DNSError 之外,还有下面内置错误结构体:
上面错误除了实现了 Error() 接口,还实现了
Timeout() bool
和Temporary() bool
接口,也就是实现了net.Error
接口同时也实现了
Unwarp()
接口,用于错误解包。那么我们就可以区分请求的错误是网络错误,还是服务器错误。比如在 jsonrpc 协议中定义了 Error 结构体,使用下面方式进行判断
如果按照以前的方式不断通过接口断言的解包错误的形式,那么代码很快会形成类似”回调地狱“的模样。
所以,在实际应用层开发上,直接可以使用
fmt.Errorf("Stack: %w",err)
包装错误,最后调用方最后使用errros.As
或errros.Is
解包按需处理错误。