前言
有时需要在处理请求前后,分别读取request.body
和response.writer
,在比如记录日志或其他场景使用,这里记录一下在使用gin时,如何获取且不影响正常请求
示例程序
这里是使用gin
web框架构建一个项目。拥有一个POST方法,在DoPost
业务方法前有一个middleware方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
func main() {
r := gin.Default()
r.POST("/test", MiddleFunc, DoPost, After)
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
func MiddleFunc(c *gin.Context) {
c.Next()
}
func DoPost(c *gin.Context) {
body, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
log.Fatalf("read body failed at Before,err:%s", err.Error())
}
var req Body
if err = json.Unmarshal(body, &req); err != nil {
log.Fatalf("json unmarshal failed, body:%s, err:%s", string(body), err.Error())
}
c.JSON(http.StatusOK, fmt.Sprintf("this is response, get body id:%s", req.Id))
}
type Body struct {
Id string `json:"id"`
}
|
通过curl请求会得到一个正常的返回
1
2
3
4
5
6
7
| curl --location --request POST 'localhost:8080/test' \
--header 'Content-Type: application/json' \
--data-raw '{
"id":"333"
}'
# 返回
"this is response, get body id:333"
|
获取request.body
这里正常读取body就可以,需要注意的是需要对request.body
重新进行赋值,否则DoPost
里会读取不到body的内容
1
2
3
4
5
6
7
| body, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
log.Fatalf("read body failed at Before,err:%s", err.Error())
}
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
log.Println("read body: ", string(body))
c.Next()
|
获取response.writer
这里主要是通过go的interface特性,通过实现http.ResponseWriter
对象的方法来替换原类型。
如下代码中,通过Write
方法,把写入body中的内容多写一份到buf
字段,读取的时候使用r.buf.String()
即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| type LogResponseWriter struct {
buf *bytes.Buffer
writer http.ResponseWriter
}
func NewLogResponseWriter(r gin.ResponseWriter) *LogResponseWriter {
return &LogResponseWriter{
buf: new(bytes.Buffer),
writer: r,
}
}
func (r *LogResponseWriter) Header() http.Header {
return r.writer.Header()
}
func (r *LogResponseWriter) Write(b []byte) (int, error) {
r.buf = bytes.NewBuffer(b)
return r.writer.Write(b)
}
func (r *LogResponseWriter) WriteHeader(statusCode int) {
r.writer.WriteHeader(statusCode)
}
|
由于本文中因为使用的是gin框架,所以除了要实现上述对象的方法外,还需要实现gin.ResponseWriter
接口。LogResponseWriter
结构更改为如下方式
1
2
3
4
| type LogResponseWriter struct {
buf *bytes.Buffer
writer gin.ResponseWriter
}
|
MiddleFunc
方法添加如下内容
1
2
3
4
5
6
7
8
9
| // 初始化对象
r := NewLogResponseWriter(c.Writer)
// 替换原来的`*gin.Context`对象中`writer`对象
c.Writer = r
// 继续进行业务处理
c.Next()
// 打印response的body信息
log.Println("response body:", r.buf.String())
|
完整代码
完整代码