英文:
Managing errors in golang
问题
我来自Ruby,目前正在研究Go语言。我开始编写一小段代码来检查给定主机的TLS支持。
var tls_versions = map[uint16]string{
tls.VersionSSL30: "SSLv3",
tls.VersionTLS10: "TLSv1.0",
tls.VersionTLS11: "TLSv1.1",
tls.VersionTLS12: "TLSv1.2",
}
var refused_re = regexp.MustCompile(": connection refused")
var nodns_re = regexp.MustCompile(": no such host")
var versionnotsupported_re = regexp.MustCompile(": protocol version not supported")
func checkversion(host string) (map[string]bool, error) {
ret := map[string]bool{}
for version := tls.VersionSSL30; version <= tls.VersionTLS12; version++ {
conn, err := tls.Dial("tcp", host+":443", &tls.Config{
MinVersion: uint16(version),
})
if err != nil &&
(refused_re.MatchString(err.Error()) == true || nodns_re.MatchString(err.Error()) == true) {
log.Println(err)
return ret, err
}
if err != nil && versionnotsupported_re.MatchString(err.Error()) == true {
ret[tls_versions[uint16(version)]] = false
log.Println("Not supported: "+host+" <-> "+tls_versions[uint16(version)])
}
ret[tls_versions[uint16(version)]] = true
if conn != nil {
conn.Close()
}
}
return ret, nil
}
作为来自Ruby的人,我发现这段代码中的错误处理相当丑陋,因为只要有一个拼写错误或更改,就无法得到正确的错误原因。我尝试使用反射(reflect)来解决问题,但无法达到我想要的效果。我想知道是否有什么明显的遗漏,或者这是Go语言的惯例?还是这是特定于crypto/tls库的,以避免从任何问题中恢复?
谢谢你的帮助。
英文:
I'm coming from Ruby and looking at Go at the moment. I start writing a little bit of code to check TLS support for a given host.
<pre>
var tls_versions = map[uint16]string{
tls.VersionSSL30: "SSLv3",
tls.VersionTLS10: "TLSv1.0",
tls.VersionTLS11: "TLSv1.1",
tls.VersionTLS12: "TLSv1.2",
}
var refused_re = regexp.MustCompile(": connection refused")
var nodns_re = regexp.MustCompile(": no such host")
var versionnotsupported_re = regexp.MustCompile(": protocol version not supported")
func checkversion(host string) (map[string]bool, error) { // {{
ret := map[string]bool{}
for version := tls.VersionSSL30; version <= tls.VersionTLS12; version++ {
conn, err := tls.Dial("tcp", host+":443", &tls.Config{
MinVersion: uint16(version),
})
if err != nil &&
(refused_re.MatchString(err.Error()) == true || nodns_re.MatchString(err.Error()) == true) {
log.Println(err)
return ret, err
}
if err != nil && versionnotsupported_re.MatchString(err.Error()) == true {
ret[tls_versions[uint16(version)]] = false
log.Println("Not supported: "+host+" <-> "+tls_versions[uint16(version)])
}
ret[tls_versions[uint16(version)]] = true
if conn != nil {
conn.Close()
}
}
return ret, nil
}
</pre>
Coming from Ruby I found the error management in this code pretty ugly as I'm one typo/change away from not getting the right reason for the error. I tried to play with reflect but couldn't get it to do what I wanted. I was wondering if I was missing something obvious or if it was the go way? Or is it specific to the crypto/tls library to avoid recovering from any issue?
Thanks for your help.
答案1
得分: 3
Go语言中有很好的错误管理可能性。
可以参考Dave C的这个答案,其中有一个很好的总结和示例。
不幸的是,在tls
包的情况下,你运气不好。你尝试检测的错误是由fmt.Errorf()
调用生成的(它们委托给errors.New()
),所以它们在任何方面都不特殊,也没有预先声明,所以你不能比你当前的解决方案更好地区分它们。可能开发人员懒得提供更复杂或更容易追踪的错误,或者他们认为这不重要,为了简单起见而省略了;所以它们目前更像是对开发人员的信息提供。
进一步阅读(引用自Dave C的答案):
英文:
There is possibility for good error management in Go.
See this answer by Dave C for a nice summary and good examples.
Unfortunately in case of the tls
package, you're out of luck. The errors you try to detect are generated by fmt.Errorf()
calls (which delegate to errors.New()
) so they are not special in any way and they are not pre-declared so you can't do significantly better than your current solution to distinguish them. Probably the developers were lazy to provide more sophisticated or more easily traceable errors or simply they thought it is not important and left out for simplicity; so they currently serve more like informational for the developer.
Further reading (quoted from Dave C's answer):
- Effective Go on errors
- The Go Blog Error handling and Go
- Dave Cheney Inspecting Errors
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论