我如何可以在一个处理程序中使用http.Request?

时间:2019-11-28 13:01:22

标签: go middleware

我有一个基本的中间件,它是一个Logger函数,当我在接下来的每个函数中执行body, err := ioutil.ReadAll(r.Body)时,http.Request将为空。但是我希望身体包含信息。我该怎么办?

开始:

r.HandleFunc("/login", server.Loger(server.GetTokenHandler()).ServeHTTP).Methods("POST")

所以是中间装:

func (server Server) Loger(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        body, _ := ioutil.ReadAll(r.Body)
        server.Log.Info(r.URL, " Methods: ", r.Method, string(body))
        h.ServeHTTP(w, r) //Calls handler h
    })
}

现在r.Body将为空:

func (server Server) GetTokenHandler()  http.Handler{
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        body, err := ioutil.ReadAll(r.Body)
        if err != nil{
            http.Error(w, "", 400)
            server.Log.Error(err)
            return
        }
        fmt.Print(string(body))
    })
}

1 个答案:

答案 0 :(得分:0)

r.Body只能读取一次。没有其他办法了。

如果需要多个中间件访问数据,则需要将其保存一个字节片并将其传递给后续的中间件。

如果处理程序具有上下文,则可以将主体数据作为上下文中的值传递。

另一种解决方案是破解,是将数据存储在ReponseWriter的标头字段中。返回时,请不要忘记删除它,以免将其发送出去。随后的中间件随后可以访问标头中的数据。

func (server Server) ReadBody(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        body, _ := ioutil.ReadAll(r.Body)
        w.Header().Add("body", string(body))
        h.ServeHTTP(w, r) //Calls handler h
        w.Header().Del("body")
    })
}

随后的中间件将通过指令data := w.Header().Get("body")获取主体数据。请注意,标头值是一个字符串,而不是字节片。