8

在普通的 Go HTTP 处理程序上,如果我在仍然写入响应的同时断开客户端连接,http.ResponseWritter.Write将返回错误消息,如write tcp 127.0.0.1:60702: connection reset by peer.

现在从syscall包裹中,我有sysca.ECONNRESET,其中有 message connection reset by peer,所以它们并不完全相同。

我怎样才能匹配它们,所以我知道如果发生它不要惊慌?在其他场合我一直在做

if err == syscall.EAGAIN {
  /* handle error differently */
}

例如,效果很好,但我不能用syscall.ECONNRESET.

更新:

因为我迫切需要一个解决方案,所以暂时我会做这个非常肮脏的黑客:

if strings.Contains(err.Error(), syscall.ECONNRESET.Error()) {
    println("it's a connection reset by peer!")
    return
}
4

4 回答 4

13

例如,您得到的错误具有基础类型*net.OpError在此处构建。

您应该能够将错误类型断言为其具体类型,如下所示:

operr, ok := err.(*net.OpError)

然后访问它的Err字段,这应该对应于您需要的系统调用错误:

operr.Err.Error() == syscall.ECONNRESET.Error()
于 2013-11-12T13:30:52.193 回答
10

我遇到了这个问题,接受的答案足以为我指明正确的方向。但是,它提供的用于检查嵌入的错误是否不完整的代码*net.OpErrorECONNRESET不完整的,至少对于 Golang 1.9 来说不是。

嵌入的错误OpError.Err实际上是类型*os.SyscallErrorhttps://golang.org/pkg/os/#SyscallError)。Write()struct 实现的函数(*net.netFD通过网络发送响应时写入的函数)如下所示:

func (fd *netFD) Write(p []byte) (nn int, err error) {
    nn, err = fd.pfd.Write(p)
    runtime.KeepAlive(fd)
    return nn, wrapSyscallError("write", err)
}

和 wrapSyscallError:

func wrapSyscallError(name string, err error) error {
    if _, ok := err.(syscall.Errno); ok {
        err = os.NewSyscallError(name, err)
    }
    return err
}

结构内部的错误*os.SyscallError可以直接与 syscall.ECONNRESET 进行比较。

因此,给定从网络写入返回的错误(例如对 的调用http.ResponseWritter.Write),确定该错误是否为 ECONNRESET 的完整代码块是:

if opErr, ok := err.(*net.OpError); ok {
    if syscallErr, ok := opErr.Err.(*os.SyscallError); ok {
        if syscallErr.Err == syscall.ECONNRESET {
            fmt.Println("Found a ECONNRESET")
        }
    }
}
于 2018-04-13T17:39:44.430 回答
8

@zian 的答案比接受的答案更有用,但现在在 Go 1.13+ 上,最好避免手动解包错误:

if errors.Is(opErr,syscall.ECONNRESET) {
    fmt.Println("Found a ECONNRESET")
}

这样做的好处是您还可以更普遍地使用它,例如在以下情况下:

resp, err := http.Get("http://127.0.0.1:4444")

在这里,这个错误将有一个额外的包装层 ( *url.Error),并且会被 @zian 使用的条件错过,而无需第三次显式打开它。

于 2020-09-30T22:46:56.007 回答
2

@zian - 感谢您对 João Pinto(和我的)问题的良好解决方案:我怎样才能匹配它们,所以我知道如果发生这种情况不要惊慌?在 go 版本 1.13 中,一个改进是使用 errors.Is 函数,它可以“在后台”按顺序进行错误解包和测试。例如 :

if errors.Is(opErr,syscall.ECONNRESET) {
  fmt.Println("Found a ECONNRESET")
}

@SteveCoffman - 加入你的好答案,干杯!

在 Go 1.13 中处理错误 - Go 博客 - Golang

于 2020-12-29T23:32:26.350 回答