「Go框架」gin框架是如何做崩潰處理的?

Go學堂發表於2023-05-18

大家好,我是漁夫子

本文我們介紹下recover在gin框架中的應用。
首先,在golang中,如果在子協程中遇到了panic,那麼主協程也會被終止。如下:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    // 在子協程中引起panic,主協程也會退出
    go func() {
        panic("hello world")
    }()
    
    // Listen and Server in 0.0.0.0:8080
    r.Run(":8080")
}

panic被描述為不可處理的錯誤。在web服務中就是服務會崩潰。當然,這在生產環境下是不可接受的。那麼,如何能夠做到發生panic時技能捕獲該panic又能讓服務繼續健康執行呢?

這就是golang中提供的recover函式了。recover函式能夠捕獲Panic錯誤並恢復程式的正常執行。
接下來,我們看下recover函式在gin框架中是如何應用的。

首先,要提到的就是gin框架中的recovery中介軟體。在gin中,是透過使用該中介軟體來捕獲panic,並保證服務不down機的。 如果使用gin.Default()函式進行構建gin物件,那麼預設就註冊了Recovery中介軟體。

func Default() *Engine {
    debugPrintWARNINGDefault()
    engine := New()
    //  註冊了Recovery中介軟體
    engine.Use(Logger(), Recovery())
    return engine
}

其次,我們來看下Recovery()中介軟體都做了些什麼。

Recovery()函式定義如下:

func Recovery() HandlerFunc {
    return RecoveryWithWriter(DefaultErrorWriter)
}

這裡的DefaultErrorWriter是預設的輸出端,即os.Stderr。即指錯誤的輸出到什麼地方。

接下來看RecoveryWithWriter函式中的實現

// RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one.
func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) HandlerFunc {
    if len(recovery) > 0 {
        return CustomRecoveryWithWriter(out, recovery[0])
    }
    return CustomRecoveryWithWriter(out, defaultHandleRecovery)
}

這裡有一個引數是defaultHandleRecovery,我們看下它的實現:

func defaultHandleRecovery(c *Context, err any) {
    c.AbortWithStatus(http.StatusInternalServerError)
}

就是寫入了一個代表內部伺服器錯誤的狀態碼500,並結束了本次請求。

這裡關鍵點是CustomRecoveryWithWriter的實現,程式碼很長,我們分段來看。如下:
image.png
主要分三部分:

  • 將日誌輸出到out中,這裡是上述提到的DefaultErrorWriter,即os.Stderr。
  • defer延遲執行部分。
  • c.Next()正常請求處理器部分。

這裡需要注意的點就是:

  • recover函式需要再defer中呼叫。因為defer是在函式返回時才呼叫,所以當發生panic時會導致函式返回,這樣才能捕獲panic。
  • 作為中介軟體執行,說明每次請求的處理器都被中介軟體包裝了,也就相當於每個請求處理器都有這個defer函式。
  • 在defer函式中,如果捕獲了panic,則將panic的詳細詳細記錄下來,可以傳送到指定的輸出中,即函式中指定的out引數(預設是os.Stderr),也可以指定其他的檔案或Sentry等。

在gin中,正是該中介軟體的應用,確保了web服務的健壯性。當然,其他的web框架也有同樣的機制,實現原理也是一樣的。

公眾號:Go學堂

特別說明:你的關注,是我寫下去的最大動力。點選下方公眾號卡片,直接關注。關注送《100個go常見的錯誤》pdf文件、經典go學習資料。

相關文章