1. 程式人生 > >gin框架使用註意事項

gin框架使用註意事項

sub 索引 lang string urn this efault any lan

gin框架使用註意事項

本文就說下這段時間我在使用gin框架過程中遇到的問題和要註意的事情。

錯誤處理請求返回要使用c.Abort,不要只是return

當在controller中進行錯誤處理的時候,發現一個錯誤,往往要立即返回,這個時候要記得使用gin.Context.Abort 或者其相關的函數。

類似於:

if err != nil {
        c.AbortWithStatus(500)
        return
    }

這個Abort函數本質是提前結束後續的handler鏈條,(通過將handler的下標索引直接變化為 math.MaxInt8 / 2 )但是前面已經執行過的handler鏈條(包括middleware等)還會繼續返回。

gin的Abort系列的幾個函數為:

func (c *Context) Abort()
func (c *Context) AbortWithStatus(code int)
func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{})
func (c *Context) AbortWithError(code int, err error)

gin的錯誤處理

gin本身默認加載了Recovery()的中間件,所以在不知道如何處理error的時候,可以直接panic出去

如何獲取response的body

需求來源於我要做個gin的中間件,請求進來的時候記錄一下請求參數,請求出去的時候記錄一下請求返回值。在記錄請求返回值的時候,我就需要得到請求的返回內容。但是context裏面只有一個結構:

Writer    gin.ResponseWriter

所以這裏基本思路就是創建一個Writer,它繼承gin.ResponseWriter。同時,它又有一個byte.buffer來copy一份數據。

// bodyLogWriter是為了記錄返回數據到log中進行了雙寫
type bodyLogWriter struct {
    gin.ResponseWriter
    body *bytes.Buffer
}

func (w bodyLogWriter) Write(b []byte) (int, error) {
    w.body.Write(b)
    return w.ResponseWriter.Write(b)
}

所以,在middleware中就應該這麽寫

sTime := time.Now()

blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
c.Writer = blw

c.Next()

// 請求結束的時候記錄
duration := fmt.Sprintf("%fms", float64(time.Now().Sub(sTime).Nanoseconds()) / 1000000.0)
handler.Tracef(c.Request.Context(), logger.DLTagRequestOut,
    "proc_time=%s||response=%s",
    duration,
    blw.body.String())

主要就是在Next之前吧context.Writer用我們定義的Writer給替換掉,讓它輸出數據的時候寫兩份。

如何獲取所有的請求參數

這個其實和gin框架沒有啥關系,我剛開始使用的時候以為使用request.ParseForm,然後在request.Form中就能得到了。

結果發現當我的Content-type為multipart/form-data的時候,竟然解析不到數據。

追到ParseForm裏面發現,http/request.go裏面有這麽一個部分代碼

case ct == "multipart/form-data":
    // handled by ParseMultipartForm (which is calling us, or should be)
    // TODO(bradfitz): there are too many possible
    // orders to call too many functions here.
    // Clean this up and write more tests.
    // request_test.go contains the start of this,
    // in TestParseMultipartFormOrder and others.
}

我的golang版本是1.11.4。當content-type為multipart/form-data的時候是空的調用的。

當然註釋也寫很清楚了,建議使用ParseMultipartForm

所以獲取http參數的函數我就寫成這個樣子:

// 這個函數只返回json化之後的數據,且不處理錯誤,錯誤就返回空字符串
func getArgs(c *gin.Context) []byte {
    if c.ContentType() == "multipart/form-data" {
        c.Request.ParseMultipartForm(defaultMemory)
    } else {
        c.Request.ParseForm()
    }
    args, _ := json.Marshal(c.Request.Form)
    return args
}

gin框架使用註意事項