Description
在给gin
服务添加超时控制的时候,由于一个接口需要返回重定向,然后导致了进程panic
,怀疑是
// Redirect returns an HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string) {
c.Render(-1, render.Redirect{
Code: code,
Location: location,
Request: c.Request,
})
}
返回-1导致的,请问一下这里为啥写死是-1? 报错信息
Error:invalid http status code: -1
Call Stack:/gopath/pkg/mod/[github.com/gin-contrib/timeout@v0.0.3/timeout.go:63](http://github.com/gin-contrib/timeout@v0.0.3/timeout.go:63) (0xe89731)
How to reproduce
func timeoutResponse(c *gin.Context) {
c.JSON(http.StatusGatewayTimeout, gin.H{
"code": 12,
"msg": "timeout",
})
}
// Timeout timeout中间件
// sample: [0, 100] 表示采样比例,可以通过修改采样比例来灰度
func Timeout(sample int32) gin.HandlerFunc {
num := rand.Int31n(101)
if num < sample {
return timeout.New(
timeout.WithTimeout(6*time.Second),
timeout.WithHandler(func(c *gin.Context) {
c.Next()
}),
timeout.WithResponse(timeoutResponse),
)
}
return func(c *gin.Context) {
c.Next()
}
}
Expectations
返回504 timeout
Actual result
panic
Environment
- go version: 1.18
- gin version (or commit ref): 1.8.1
- operating system: linux
Comment From: fatelei
please apply panic traceback
Comment From: BigeYoung
Test Code
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"time"
"github.com/gin-contrib/timeout"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Use(timeout.New(
timeout.WithTimeout(time.Second),
timeout.WithHandler(func(c *gin.Context) {
c.Next()
}),
timeout.WithResponse(func(c *gin.Context) {
c.AbortWithStatus(http.StatusGatewayTimeout)
}),
))
r.GET("/redirect", func(c *gin.Context) {
c.Redirect(http.StatusFound, "https://www.github.com/")
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/redirect", nil)
r.ServeHTTP(w, req)
fmt.Print(w.Body.String())
}
Result:
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /redirect --> main.main.func3 (4 handlers)
2023/06/01 12:01:27 [Recovery] 2023/06/01 - 12:01:27 panic recovered:
GET /redirect HTTP/1.1
invalid http status code: -1
/Users/xxx/go/pkg/mod/github.com/gin-contrib/timeout@v0.0.3/timeout.go:63 (0x1027f6be3)
New.func1: panic(p)
/Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f110f)
(*Context).Next: c.handlers[c.index](c)
/Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/recovery.go:102 (0x1027f10f0)
CustomRecoveryWithWriter.func1: c.Next()
/Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f037f)
(*Context).Next: c.handlers[c.index](c)
/Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/logger.go:240 (0x1027f035c)
LoggerWithConfig.func1: c.Next()
/Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027ef497)
(*Context).Next: c.handlers[c.index](c)
/Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:620 (0x1027ef16c)
(*Engine).handleHTTPRequest: c.Next()
/Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:576 (0x1027eeec7)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/Users/xxx/Desktop/gorm-playground/main.go:30 (0x1027f79ef)
main: r.ServeHTTP(w, req)
/usr/local/go/src/runtime/proc.go:250 (0x1025d180f)
main: fn()
/usr/local/go/src/runtime/asm_arm64.s:1270 (0x1025fe833)
goexit: MOVD R0, R0 // NOP
[GIN] 2023/06/01 - 12:01:27 | 500 | 1.914833ms | | GET "/redirect"
Comment From: fatelei
go StatusGatewayTimeout
-1 is not a valid http status code
Comment From: x-lambda
Test Code
```go package main
import ( "fmt" "net/http" "net/http/httptest" "time"
"github.com/gin-contrib/timeout" "github.com/gin-gonic/gin" )
func main() { r := gin.Default() r.Use(timeout.New( timeout.WithTimeout(time.Second), timeout.WithHandler(func(c gin.Context) { c.Next() }), timeout.WithResponse(func(c gin.Context) { c.AbortWithStatus(http.StatusGatewayTimeout) }), )) r.GET("/redirect", func(c *gin.Context) { c.Redirect(http.StatusFound, "https://www.github.com/") })
w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/redirect", nil) r.ServeHTTP(w, req)
fmt.Print(w.Body.String()) } ```
Result:
``` [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /redirect --> main.main.func3 (4 handlers)
2023/06/01 12:01:27 [Recovery] 2023/06/01 - 12:01:27 panic recovered: GET /redirect HTTP/1.1
invalid http status code: -1 /Users/xxx/go/pkg/mod/github.com/gin-contrib/timeout@v0.0.3/timeout.go:63 (0x1027f6be3) New.func1: panic(p) /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f110f) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/recovery.go:102 (0x1027f10f0) CustomRecoveryWithWriter.func1: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f037f) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/logger.go:240 (0x1027f035c) LoggerWithConfig.func1: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027ef497) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:620 (0x1027ef16c) (Engine).handleHTTPRequest: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:576 (0x1027eeec7) (*Engine).ServeHTTP: engine.handleHTTPRequest(c) /Users/xxx/Desktop/gorm-playground/main.go:30 (0x1027f79ef) main: r.ServeHTTP(w, req) /usr/local/go/src/runtime/proc.go:250 (0x1025d180f) main: fn() /usr/local/go/src/runtime/asm_arm64.s:1270 (0x1025fe833) goexit: MOVD R0, R0 // NOP
[GIN] 2023/06/01 - 12:01:27 | 500 | 1.914833ms | | GET "/redirect" ```
我看了是其实是github.com/gin-contrib/timeout
库的问题,gin
使用-1
跳过状态码赋值,但是这个库没有处理,参考这个老哥的pr https://github.com/gin-contrib/timeout/pull/37/files
Comment From: fatelei
Test Code ```go package main
import ( "fmt" "net/http" "net/http/httptest" "time"
"github.com/gin-contrib/timeout" "github.com/gin-gonic/gin"
)
func main() { r := gin.Default() r.Use(timeout.New( timeout.WithTimeout(time.Second), timeout.WithHandler(func(c gin.Context) { c.Next() }), timeout.WithResponse(func(c gin.Context) { c.AbortWithStatus(http.StatusGatewayTimeout) }), )) r.GET("/redirect", func(c *gin.Context) { c.Redirect(http.StatusFound, "https://www.github.com/") })
w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/redirect", nil) r.ServeHTTP(w, req) fmt.Print(w.Body.String())
} ```
Result: ``` [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /redirect --> main.main.func3 (4 handlers)
2023/06/01 12:01:27 [Recovery] 2023/06/01 - 12:01:27 panic recovered: GET /redirect HTTP/1.1
invalid http status code: -1 /Users/xxx/go/pkg/mod/github.com/gin-contrib/timeout@v0.0.3/timeout.go:63 (0x1027f6be3) New.func1: panic(p) /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f110f) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/recovery.go:102 (0x1027f10f0) CustomRecoveryWithWriter.func1: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f037f) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/logger.go:240 (0x1027f035c) LoggerWithConfig.func1: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027ef497) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:620 (0x1027ef16c) (Engine).handleHTTPRequest: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:576 (0x1027eeec7) (*Engine).ServeHTTP: engine.handleHTTPRequest(c) /Users/xxx/Desktop/gorm-playground/main.go:30 (0x1027f79ef) main: r.ServeHTTP(w, req) /usr/local/go/src/runtime/proc.go:250 (0x1025d180f) main: fn() /usr/local/go/src/runtime/asm_arm64.s:1270 (0x1025fe833) goexit: MOVD R0, R0 // NOP
[GIN] 2023/06/01 - 12:01:27 | 500 | 1.914833ms | | GET "/redirect" ```
我看了是其实是
github.com/gin-contrib/timeout
库的问题,gin
使用-1
跳过状态码赋值,但是这个库没有处理,参考这个老哥的prhttps://github.com/gin-contrib/timeout/pull/37/files
so this is a gin bug
Comment From: x-lambda
Test Code ```go package main
import ( "fmt" "net/http" "net/http/httptest" "time"
"github.com/gin-contrib/timeout" "github.com/gin-gonic/gin" )
func main() { r := gin.Default() r.Use(timeout.New( timeout.WithTimeout(time.Second), timeout.WithHandler(func(c gin.Context) { c.Next() }), timeout.WithResponse(func(c gin.Context) { c.AbortWithStatus(http.StatusGatewayTimeout) }), )) r.GET("/redirect", func(c *gin.Context) { c.Redirect(http.StatusFound, "https://www.github.com/") })
w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/redirect", nil) r.ServeHTTP(w, req)
fmt.Print(w.Body.String()) } ```
Result: ``` [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /redirect --> main.main.func3 (4 handlers)
2023/06/01 12:01:27 [Recovery] 2023/06/01 - 12:01:27 panic recovered: GET /redirect HTTP/1.1
invalid http status code: -1 /Users/xxx/go/pkg/mod/github.com/gin-contrib/timeout@v0.0.3/timeout.go:63 (0x1027f6be3) New.func1: panic(p) /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f110f) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/recovery.go:102 (0x1027f10f0) CustomRecoveryWithWriter.func1: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f037f) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/logger.go:240 (0x1027f035c) LoggerWithConfig.func1: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027ef497) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:620 (0x1027ef16c) (Engine).handleHTTPRequest: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:576 (0x1027eeec7) (*Engine).ServeHTTP: engine.handleHTTPRequest(c) /Users/xxx/Desktop/gorm-playground/main.go:30 (0x1027f79ef) main: r.ServeHTTP(w, req) /usr/local/go/src/runtime/proc.go:250 (0x1025d180f) main: fn() /usr/local/go/src/runtime/asm_arm64.s:1270 (0x1025fe833) goexit: MOVD R0, R0 // NOP
[GIN] 2023/06/01 - 12:01:27 | 500 | 1.914833ms | | GET "/redirect" ```
我看了是其实是
github.com/gin-contrib/timeout
库的问题,gin
使用-1
跳过状态码赋值,但是这个库没有处理,参考这个老哥的prhttps://github.com/gin-contrib/timeout/pull/37/files
so this is a gin bug
gin
在
// Redirect returns an HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string) {
c.Render(-1, render.Redirect{
Code: code,
Location: location,
Request: c.Request,
})
}
写死的-1
会修改吗?
Comment From: BigeYoung
Test Code ```go package main
import ( "fmt" "net/http" "net/http/httptest" "time"
"github.com/gin-contrib/timeout" "github.com/gin-gonic/gin"
)
func main() { r := gin.Default() r.Use(timeout.New( timeout.WithTimeout(time.Second), timeout.WithHandler(func(c gin.Context) { c.Next() }), timeout.WithResponse(func(c gin.Context) { c.AbortWithStatus(http.StatusGatewayTimeout) }), )) r.GET("/redirect", func(c *gin.Context) { c.Redirect(http.StatusFound, "https://www.github.com/") })
w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/redirect", nil) r.ServeHTTP(w, req) fmt.Print(w.Body.String())
} ```
Result: ``` [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /redirect --> main.main.func3 (4 handlers)
2023/06/01 12:01:27 [Recovery] 2023/06/01 - 12:01:27 panic recovered: GET /redirect HTTP/1.1
invalid http status code: -1 /Users/xxx/go/pkg/mod/github.com/gin-contrib/timeout@v0.0.3/timeout.go:63 (0x1027f6be3) New.func1: panic(p) /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f110f) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/recovery.go:102 (0x1027f10f0) CustomRecoveryWithWriter.func1: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027f037f) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/logger.go:240 (0x1027f035c) LoggerWithConfig.func1: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/context.go:174 (0x1027ef497) (Context).Next: c.handlersc.index /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:620 (0x1027ef16c) (Engine).handleHTTPRequest: c.Next() /Users/xxx/go/pkg/mod/github.com/gin-gonic/gin@v1.9.1/gin.go:576 (0x1027eeec7) (*Engine).ServeHTTP: engine.handleHTTPRequest(c) /Users/xxx/Desktop/gorm-playground/main.go:30 (0x1027f79ef) main: r.ServeHTTP(w, req) /usr/local/go/src/runtime/proc.go:250 (0x1025d180f) main: fn() /usr/local/go/src/runtime/asm_arm64.s:1270 (0x1025fe833) goexit: MOVD R0, R0 // NOP
[GIN] 2023/06/01 - 12:01:27 | 500 | 1.914833ms | | GET "/redirect" ```
我看了是其实是
github.com/gin-contrib/timeout
库的问题,gin
使用-1
跳过状态码赋值,但是这个库没有处理,参考这个老哥的prhttps://github.com/gin-contrib/timeout/pull/37/files
是啊,github.com/gin-contrib/timeout
这个库好多issue和pr都没有处理。相比之下github.com/vearne/gin-timeout
活跃得多,相同的问题重定向异常,维护者一天就修复了。gin社区是否可以考虑将github.com/vearne/gin-timeout
这个库加入到gin-contrib?