I want to add a uniform response header to all the processing functions, but it does not work
As shown in the figure below, I want to add a custom header "X-TIME" after the processing is completed, but it does not work.
package main
import "github.com/gin-gonic/gin"
func main() {
r:=gin.Default()
g:=r.Group("/res", func(context *gin.Context) {
context.Next()
//I want to add a unified response header here,
//but it is invalid.
context.Header("X-TIME","time")
})
g.GET("/", func(context *gin.Context) {
//it is valid.
context.Header("X-KEY","key")
context.JSON(200,gin.H{
"key":"value",
})
})
r.Run(":18080")
}
Comment From: binbin0325
gin: v1.4.0 golang: 1.14.2 @QueryHeaven I tested it and it seemed to work well.
func SetupRouter() *gin.Engine {
router := gin.Default()
v1 := router.Group("/v1", func(c *gin.Context) {
c.Next()
c.Header("X-TIME", "time")
})
{
v1.Any("/log", services.Get)
}
return router
}
Comment From: QueryHeaven
go 1.12
gin v1.6.3
@sanxun0325 I don't know how it is written in your services.Get,
I tested again and found the following:
Comment From: joaohaas
Kind of necroing, but since this is still open, the reason headers don't get written is due to the way Go internals handles response buffering. As soon as a status header (aka status code) is written, the response starts getting written to a buffer, and extra headers cannot be written.
In most cases, you can just add the header before the c.Next()
call and it will work. If you need to write the header after the status code is written, you'll need to hijack the writer and override the WriteHeader
function:
type afterMiddlewareWriter struct {
gin.ResponseWriter
}
func (w *afterMiddlewareWriter) WriteHeader(statusCode int) {
w.Header().Add("X-TIME", "time")
w.ResponseWriter.WriteHeader(statusCode)
}
func AfterMiddleware(c *gin.Context) {
c.Writer = &afterMiddlewareWriter{c.Writer}
c.Next()
}
func main() {
r := gin.Default()
r.Use(AfterMiddleware)
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"key": "value",
})
})
}
For a real X-Time
implementation, you can store the initial time on your struct and calculate how many seconds have passed in the hijacked WriteHeader
.
Comment From: coanor
For my case, it's simple to add customize header in response:
router := gin.New()
router.Use(func(c *gin.Context) {
c.Header("X-Your-Header-Name", "your-header-value")
})
// some other middleware...
// add router
router.GET("/some/api", apiHandler)
... // more
Comment From: maxant
here is a more complete version of @joaohaas 's suggestion:
type timingMiddlewareWriter struct {
gin.ResponseWriter
start time.Time
}
func (w *timingMiddlewareWriter) WriteHeader(statusCode int) {
elapsed := time.Since(w.start)
log.Debug().Msg("timer ended after writing statusCode: " + elapsed.String())
w.Header().Add("x-time", elapsed.String())
w.ResponseWriter.WriteHeader(statusCode)
}
func timingMiddleware(c *gin.Context) {
log.Debug().Msg("timer starting...")
c.Writer = &timingMiddlewareWriter{ c.Writer, time.Now()}
c.Next()
log.Debug().Msg("timer ended after next()")
}