timeout
timeout copied to clipboard
Headers get overwritten if using multiple custom middlewares
If you use multiple custom middlewares then the timeout middleware will overwrite previous status codes.
package main
import (
"log"
"net/http"
"time"
"github.com/gin-contrib/timeout"
"github.com/gin-gonic/gin"
)
func testResponse(c *gin.Context) {
c.String(http.StatusRequestTimeout, "timeout")
}
// custom middleware straight from example
func timeoutMiddleware() gin.HandlerFunc {
return timeout.New(
timeout.WithTimeout(500*time.Millisecond),
timeout.WithHandler(func(c *gin.Context) {
c.Next()
}),
timeout.WithResponse(testResponse),
)
}
// simple middleware to always throw a 401
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.AbortWithStatus(401)
return
}
}
func main() {
r := gin.New()
// middleware
r.Use(gin.Logger())
r.Use(timeoutMiddleware()) // 1. timeout middleware
r.Use(authMiddleware()) // 2. auth middleware
r.Use(gin.Recovery()) // recommend to use this middleware to recover from any panics in the handlers.
r.GET("/", func(c *gin.Context) {
time.Sleep(1000 * time.Millisecond)
c.String(http.StatusOK, "Hello world!")
})
if err := r.Run(":8080"); err != nil {
log.Fatal(err)
}
}
result:
HTTP/1.1 200 OK
gin logs:
[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 200 with 401
[GIN] 2022/08/25 - 16:58:19 | 401 | 25.583µs | 127.0.0.1 | GET "/"
If you change the order of the middlewares then the timeout never applies correctly.
We swapped to https://github.com/vearne/gin-timeout and the issue doesn't occur there.