I want to rewrite response body in middleware, but I found it is difficult, Beacuse I must rewrite all of the method of the interface "ResponseWrite", have any simple method to rewrite response body?
Comment From: 0x2d3c
are you want to resize response data? if that, this code may help you
type copyWriter struct {
gin.ResponseWriter
buf *bytes.Buffer
}
func (cw copyWriter) Write(b []byte) (int, error) {
return cw.buf.Write(b)
}
func main() {
engine := gin.New()
engine.Use(func(ctx *gin.Context) {
cw := ©Writer{buf: &bytes.Buffer{}, ResponseWriter: ctx.Writer}
ctx.Writer = cw
ctx.Next()
// read data in buf
// do something for data
// write to ResponseWriter
})
engine.GET("hi", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"msg": "hello"})
})
engine.Run()
}
Comment From: seifchen
Yes, Thanks
Comment From: nishyt
@seifchen @0x2d3c can you please explain how to write the modified response back to the client (browser / curl)
For example : How would I update the JSON from{"msg": "hello"}
to {"msg": "nice"}
and get the new response when I run the command : curl -vk http://localhost:8080/hi
Comment From: seifchen
@nishyt there is the test code
type BodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
in middleware to rewrite the body: `
fmt.Printf("PostHandler login_name:%s\n", c.Request.Header.Get("staffname"))
var wb *BodyWriter // define a new writer
if w, ok := c.Writer.(gin.ResponseWriter); ok {
fmt.Println("ok")
wb = NewBodyWriter(w)
c.Writer = wb
c.Next()
} else {
c.Next()
return
}
status := wb.Status()
// read the response
data := wb.body.String()
// rewrite the response
wb.ResponseWriter.WriteString(`{"seifchen":"success"}`)
wb.body.Reset()
data2 := wb.body.String()
fmt.Printf("PostHandler stats:%v, data:%s,data2:%s", status, data, data2)
`
Comment From: nishyt
@seifchen . Thanks a lot for your help . I tried implementing the above code but to make it work I had to rewrite the all methods of interface "ResponseWriter". Is there any better way to implement the same. Can you point me to complete code (if any) for this
Comment From: seifchen
@nishyt define the struct ,had not to rewrite all methods of interface "ResponseWriter"
type BodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
Comment From: nishyt
@seifchen . Here's the program I wrote as per you recommendation . Here I want to modify the JSON {"name": "OLD_NAME", "work": "OLD_WORK"}
to {"name": "NEW_NAME", "work": "NEW_WORK"}
.
package main
import (
"bytes"
"encoding/json"
"net/http"
"github.com/gin-gonic/gin"
)
type BodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func main() {
r := gin.Default()
r.Use(TestMiddleware())
r.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"name": "OLD_NAME",
"work": "OLD_WORK",
})
})
r.Run(":8080")
}
func TestMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
wb := &BodyWriter{
body: &bytes.Buffer{},
ResponseWriter: c.Writer,
}
c.Writer = wb
c.Next()
data := wb.body.String()
obj := make(map[string]interface{})
json.Unmarshal([]byte(data), &obj)
obj["name"] = "NEW_NAME"
obj["work"] = "NEW_WORK"
updatedBody, _ := json.Marshal(obj)
wb.ResponseWriter.WriteString(string(updatedBody))
wb.body.Reset()
}
}
But when I run the program (go run main.go) and in the other terminal execute the command :curl -vk http://localhost:8080/test
, I get the following response body
{"name":"OLD_NAME","work":"OLD_WORK"}{"name":"NEW_NAME","work":"NEW_WORK"}
. It's appending the updated response on to the previous response but I only want the updated response
Comment From: seifchen
@0x2d3c you should rewrite Write method like this
func (w BodyWriter) Write(b []byte) (int, error) {
return w.body.Write(b)
}
Comment From: nishyt
@seifchen Thanks a lot for your help. It worked :)
Comment From: kuustudio
@seifchen According to your proposal, when I want to response []byte
type content, the result cannot be output. I tried c.Data(http.StatusOK, "text/plain", []byte("Test"))
and wb.Write([]byte("Test"))
.
Comment From: seifchen
@kuustudio you should use wb.ResponseWriter.Write([]byte("Test"))
Comment From: kuustudio
@seifchen
Thanks a lot for your help. It worked :)
Comment From: manuelarte
I am trying with the following code and I can't make it to rewrite the response:
type bodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func(c *gin.Context) {
wb := &bodyWriter{
body: &bytes.Buffer{},
ResponseWriter: c.Writer,
}
c.Writer = wb
c.Next()
data := wb.body.String()
wb.ResponseWriter.WriteString(`{"seifchen":"success"}`)
wb.body.Reset()
data2 := wb.body.String()
fmt.Printf("PostHandler data:%s,data2:%s", data, data2)
}
I get an empty string in data2, any idea what am I doing wrong?