在普通的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
}
答案 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.SyscallError
(https://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 - 补充你的好答案,干杯!
答案 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的条件会错过该错误。