3 回答
TA贡献1851条经验 获得超5个赞
惯用的方法是检查错误返回调用链。
要从任何地方退出处理程序,请按照 encoding/json 包中的模式使用 panic 和 recover 。
为恐慌定义一个独特的类型:
type httpError struct {
status int
message string
}
编写要在 defer 语句中使用的函数。该函数检查类型并适当地处理错误。否则,函数会继续恐慌。
func handleExit(w http.ResponseWriter) {
if r := recover(); r != nil {
if he, ok := r.(httpError); ok {
http.Error(w, he.message, he.status)
} else {
panic(r)
}
}
}
为调用 panic 编写一个辅助函数:
func exit(status int, message string) {
panic(httpError{status: status, message: message})
}
使用这样的功能:
func example() {
exit(http.StatusBadRequest, "Bad!")
}
func someHandler(w http.ResponseWriter, r *http.Request) {
defer handleExit(w)
example()
}
TA贡献1871条经验 获得超13个赞
我的回答: 首先,在 Golang 中建立的通用模式是让错误作为返回值从被调用者“冒泡”回到调用者。它在可读性和可重用性方面具有很多优势。副作用是有很多if err != nil {return}支票。
如果你真的想打破常规,我的建议
我要提出一个想法,我认为它在 golang 编码风格和模式方面并不常见或不标准。但我没有在网上看到任何暗示这是灾难性的事情。让我们看看我在评论中说这太糟糕了。
您可以使用runtime.Goexit()来实现您想要的。处理程序只是等待另一个 goroutine 来完成工作。如果 go-routine 中运行的内部代码想要中止处理,它可以调用 Goexit()。它的优点是所有defer语句仍将执行。
这看起来像是 Golang 目前不支持的异常处理的弱版本。但我要把它扔出去。
func handler(w http.ResponseWriter, r *http.Request) {
var cleanExit bool = false
var ch = make(chan bool)
// the actual handler implementation in a goroutine
go func() {
defer close(ch)
handlerImpl(w, r)
cleanExit = true // if handlerImpl invokes goExit, this line doesn't execute
}()
// wait for goroutine to exit
<-ch
if cleanExit {
fmt.Println("Handler exited normally")
} else {
fmt.Println("Hanlder was aborted")
}
}
func handlerImpl(w http.ResponseWriter, r *http.Request) {
checkSomeThing(w, r)
}
func checkSomeThing(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Bad Request!", http.StatusBadRequest)
runtime.Goexit()
}
TA贡献1798条经验 获得超3个赞
如果checkSomeThing()
特定于该路线,您可能应该继续使用您粘贴的代码示例。
如果checkSomeThing()
是所有路由(或路由子集)共有的函数,您可以选择一种方式在调用特定路由的处理程序之前运行中间件。
例如,请参阅此答案或此答案,或者这是一种仅使用标准 http 包中的代码来完成此操作的方法:
func checkSomething(...) error {
...
}
func WrapWithCheck(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
err := checkSomething(w, req)
if err != nil {
return
}
handler.ServeHTTP(w, req)
})
}
func setupRouter() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/foo/", handleFoo)
mux.HandleFunc("/bar/", handleBar)
mux.HandleFunc("/baz/", handleBaz)
// add your common call to 'checkSomething' here :
handler := WrapWithCheck(mux)
return handler
}
注意:我尝试httptest在上面的操场上使用,但由于某种原因它在操场上陷入僵局。sample.go如果您将此代码复制/粘贴到一个文件中并使用,它会很好地工作go run sample.go
- 3 回答
- 0 关注
- 131 浏览
添加回答
举报