背景
在返回响应报文到客户端时,需要保存整个记录。
Golang 标准库有实现:src/net/http/httptest/recorder.go
ResponseRecorder
,但是此不符合需求,会拦截 response
,不返回给客户端。想要的效果是返回给客户端的同时取得简单的响应的 response
, 需要做简单的修改
ResponseRecorder
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xhttp
import (
"bytes"
"net/http"
)
type ResponseRecorder struct {
W http.ResponseWriter
StatusCode int
Body *bytes.Buffer
}
func NewRecorder(w http.ResponseWriter) *ResponseRecorder {
return &ResponseRecorder{
W: w,
StatusCode: http.StatusOK,
Body: new(bytes.Buffer),
}
}
func (rw *ResponseRecorder) WriteHeader(statusCode int) {
rw.StatusCode = statusCode
rw.W.WriteHeader(statusCode)
}
func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
_, _ = rw.Body.Write(buf)
return rw.W.Write(buf)
}
func (rw *ResponseRecorder) Header() http.Header {
return rw.W.Header()
}
其中一个使用例子如下
package main
import (
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/vnotes/xhttp"
)
func recordMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rec := xhttp.NewRecorder(w)
next.ServeHTTP(rec, r)
log.Printf("response is %s\n", rec.Body)
log.Printf("response header is %d\n", rec.StatusCode)
})
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/api", hello)
r.Use(recordMiddleware)
_ = http.ListenAndServe(":11111", r)
}
func hello(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("hello"))
w.WriteHeader(http.StatusOK)
}
curl -X GET http://127.0.0.1:11111/api
结果为 hello
。假若使用 httptest.NewRecorder()
则结果为空。
当然,都同时会有日志打印
2020/04/04 17:40:15 response is hello
2020/04/04 17:40:15 response header is 200
coresHandlerInfoMiddleware
另外 https://github.com/gorilla/mux 典型的 middlewares
使用为 r.Use(mux.CORSMethodMiddleware(r))
例如在每次的接口调用中打印函数名:相对应的 middlewares
为
// 获取函数名
func getFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
func getHandlerName(r *mux.Router, req *http.Request) {
_ = r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
if !route.Match(req, &mux.RouteMatch{}) {
return nil
}
_handler := route.GetHandler()
fName := getFunctionName(_handler)
log.Printf("function name %s", fName)
return nil
})
}
// handler info middleware
func coresHandlerInfoMiddleware(r *mux.Router) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
getHandlerName(r, req)
next.ServeHTTP(w, req)
})
}
}
r.Use(coresHandlerInfoMiddleware(r))