处理Go中的连接重置错误

时间:2013-11-12 12:37:01

标签: error-handling go runtime-error

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

现在,从syscall包中,我有sysca.ECONNRESET,其中包含消息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 个答案:

答案 0 :(得分:9)

您获得的错误具有基础类型*net.OpError,例如构建here

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

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

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

operr.Err.Error() == syscall.ECONNRESET.Error()

答案 1 :(得分:5)

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

OpError.Err处嵌入的错误实际上是*os.SyscallErrorhttps://golang.org/pkg/os/#SyscallError)类型。 struct Write()实现的*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")
        }
    }
}

答案 2 :(得分:1)

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

{
    "name": "PowerShell: Launch script.ps1",
    "type": "PowerShell",
    "request": "launch",
    "script": ".\\script.ps1",
    "cwd": "${workspaceFolder}"
}

@SteveCoffman - 补充你的好答案,干杯!

Working with Errors in Go 1.13 - The Go Blog - Golang

答案 3 :(得分:0)

@zian的答案比公认的答案更有用,但是现在在Go 1.13+上,最好避免手动解开错误:

if errors.As(err, &syscallErr) && syscallErr.Err == syscall.ECONNRESET {
    fmt.Println("Found a ECONNRESET")
}

这样做的好处是您也可以更广泛地使用它,例如在之后使用:

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

在此情况下,此错误将另外具有一层包装(*url.Error),并且在未显式展开的情况下使用@zian的条件会错过该错误。