3 回答

TA貢獻(xiàn)1851條經(jīng)驗(yàn) 獲得超5個(gè)贊
慣用的方法是檢查錯(cuò)誤返回調(diào)用鏈。
要從任何地方退出處理程序,請(qǐng)按照 encoding/json 包中的模式使用 panic 和 recover 。
為恐慌定義一個(gè)獨(dú)特的類(lèi)型:
type httpError struct {
status int
message string
}
編寫(xiě)要在 defer 語(yǔ)句中使用的函數(shù)。該函數(shù)檢查類(lèi)型并適當(dāng)?shù)靥幚礤e(cuò)誤。否則,函數(shù)會(huì)繼續(xù)恐慌。
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)
}
}
}
為調(diào)用 panic 編寫(xiě)一個(gè)輔助函數(shù):
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貢獻(xiàn)1871條經(jīng)驗(yàn) 獲得超13個(gè)贊
我的回答: 首先,在 Golang 中建立的通用模式是讓錯(cuò)誤作為返回值從被調(diào)用者“冒泡”回到調(diào)用者。它在可讀性和可重用性方面具有很多優(yōu)勢(shì)。副作用是有很多if err != nil {return}支票。
如果你真的想打破常規(guī),我的建議
我要提出一個(gè)想法,我認(rèn)為它在 golang 編碼風(fēng)格和模式方面并不常見(jiàn)或不標(biāo)準(zhǔn)。但我沒(méi)有在網(wǎng)上看到任何暗示這是災(zāi)難性的事情。讓我們看看我在評(píng)論中說(shuō)這太糟糕了。
您可以使用runtime.Goexit()來(lái)實(shí)現(xiàn)您想要的。處理程序只是等待另一個(gè) goroutine 來(lái)完成工作。如果 go-routine 中運(yùn)行的內(nèi)部代碼想要中止處理,它可以調(diào)用 Goexit()。它的優(yōu)點(diǎn)是所有defer語(yǔ)句仍將執(zhí)行。
這看起來(lái)像是 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貢獻(xiàn)1798條經(jīng)驗(yàn) 獲得超3個(gè)贊
如果checkSomeThing()
特定于該路線(xiàn),您可能應(yīng)該繼續(xù)使用您粘貼的代碼示例。
如果checkSomeThing()
是所有路由(或路由子集)共有的函數(shù),您可以選擇一種方式在調(diào)用特定路由的處理程序之前運(yùn)行中間件。
例如,請(qǐng)參閱此答案或此答案,或者這是一種僅使用標(biāo)準(zhǔn) http 包中的代碼來(lái)完成此操作的方法:
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在上面的操場(chǎng)上使用,但由于某種原因它在操場(chǎng)上陷入僵局。sample.go如果您將此代碼復(fù)制/粘貼到一個(gè)文件中并使用,它會(huì)很好地工作go run sample.go
- 3 回答
- 0 關(guān)注
- 181 瀏覽
添加回答
舉報(bào)