亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

golang - 從任何地方退出 http 處理程序

golang - 從任何地方退出 http 處理程序

Go
aluckdog 2023-01-03 17:18:08
我正在使用 net/http 包并想知道如何從代碼中的任何位置退出處理程序。說我有這段代碼:func main() {    http.HandleFunc("/", handler)    http.ListenAndServe(":8080", nil)}func handler(w http.ResponseWriter, r *http.Request){    err := checkSomeThing(w, r)    if err != nil {        return    }    fmt.Println("End of Handler.")    return}func checkSomeThing(w http.ResponseWriter, r *http.Request) error{    http.Error(w, "Bad Request!", http.StatusBadRequest)         return errors.New("bad request")}理想情況下,我想從 checkSomeThing 函數中退出處理程序,而不必返回然后再向上返回一個級別,隨著應用程序的增長,這會變得更糟。這純粹是為了代碼可讀性。
查看完整描述

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()

}


查看完整回答
反對 回復 2023-01-03
?
慕桂英4014372

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()

}


查看完整回答
反對 回復 2023-01-03
?
呼如林

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


查看完整回答
反對 回復 2023-01-03
  • 3 回答
  • 0 關注
  • 173 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號