web-dev-qa-db-ja.com

ジンでレスポンスボディを記録する方法

応答本文をginのミドルウェアに記録する必要がありますが、応答本文を取得する方法がわかりません。誰か助けてもらえますか?

私はこのようなミドルウェアを使用しています:

func Logger() gin.HandlerFunc {

    return func(c *gin.Context) {

        c.Next()

        statusCode := c.Writer.Status()
        if statusCode >= 400 {
            //ok this is an request with error, let's make a record for it
            //log body here
        }
    }
}

私の質問は、ミドルウェアのコンテキストから応答本文を取得する方法ですか?

11
John Zeng

応答の書き込みを傍受し、最初にどこかに保存する必要があります。その後、ログに記録できます。そのためには、Write()呼び出しをインターセプトする独自のWriterを実装する必要があります。

たとえば、次のようになります。

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

func ginBodyLogMiddleware(c *gin.Context) {
    blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
    c.Writer = blw
    c.Next()
    statusCode := c.Writer.Status()
    if statusCode >= 400 {
        //ok this is an request with error, let's make a record for it
        // now print body (or log in your preferred way)
        fmt.Println("Response body: " + blw.body.String())
    }
}

次に、このミドルウェアを次のように使用します。

router.Use(ginBodyLogMiddleware)

Ginは静的ファイルにc.Writerを使用していないようであるため、このシルは静的ファイルでは機能しないことに注意してください。しかし、ほとんどの場合、それはあなたがとにかく欲しいものです。

すべてのファイルをインターセプトする場合は、もう少し複雑な方法を使用する必要があります。ミドルウェアの代わりに、gin.Engineをラップし、上記と同じアプローチを使用してhttp.ResponseWriterに書き込まれたものをインターセプトしてログに記録するラッパーhttp.Handlerを実装する必要があります。次に、次のようにginサーバーを実行します。

ginRouter := gin.New()
// configure your middleware and routes as required

// Run http server as follows, where bodyLogHandler is your wrapper handler
http.ListenAndServe(bindAddress, &bodyLogHandler{wrappedHandler: ginRouter}
18
Seva

ご参考までに

注:レスポンス本文の記述にWriteString()を使用する場合は、c.String()を実装します

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

func (w bodyLogWriter) WriteString(s string) (int, error) {
    w.body.WriteString(s)
    return w.ResponseWriter.WriteString(s)
}

func ginBodyLogMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
        c.Writer = blw
        c.Next()

        fmt.Println("Response body: " + blw.body.String())
    }
}

...

// register
router := r.Group("/", ginBodyLogMiddleware())
0
Sean