mirror of
https://github.com/gin-gonic/gin.git
synced 2026-09-12 21:05:53 +08:00
feat: add SkipMethodNotAllowedMiddleware option
Add Engine.SkipMethodNotAllowedMiddleware flag that, when enabled, prevents global middleware from running on 405 Method Not Allowed responses. This allows NoMethod handlers to respond correctly without being intercepted by middleware such as authentication or checksum validation that would otherwise reject the request first. Fixes #4189
This commit is contained in:
parent
d75fcd4c9a
commit
8b0338fc87
11
gin.go
11
gin.go
@ -122,6 +122,13 @@ type Engine struct {
|
||||
// handler.
|
||||
HandleMethodNotAllowed bool
|
||||
|
||||
// SkipMethodNotAllowedMiddleware if enabled, global middleware registered via Use()
|
||||
// will not be executed for 405 Method Not Allowed responses. This allows
|
||||
// NoMethod handlers to run without triggering middleware that may reject
|
||||
// the request (e.g., authentication, checksum validation) before the 405
|
||||
// response can be sent.
|
||||
SkipMethodNotAllowedMiddleware bool
|
||||
|
||||
// ForwardedByClientIP if enabled, client IP will be parsed from the request's headers that
|
||||
// match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was
|
||||
// fetched, it falls back to the IP obtained from
|
||||
@ -358,6 +365,10 @@ func (engine *Engine) rebuild404Handlers() {
|
||||
}
|
||||
|
||||
func (engine *Engine) rebuild405Handlers() {
|
||||
if engine.SkipMethodNotAllowedMiddleware {
|
||||
engine.allNoMethod = engine.noMethod
|
||||
return
|
||||
}
|
||||
engine.allNoMethod = engine.combineHandlers(engine.noMethod)
|
||||
}
|
||||
|
||||
|
||||
59
gin_test.go
59
gin_test.go
@ -1156,3 +1156,62 @@ func TestUpdateRouteTreesCalledOnce(t *testing.T) {
|
||||
assert.Equal(t, "ok", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Test the fix for https://github.com/gin-gonic/gin/issues/4189
|
||||
func TestSkipMethodNotAllowedMiddleware(t *testing.T) {
|
||||
g := New()
|
||||
g.HandleMethodNotAllowed = true
|
||||
g.SkipMethodNotAllowedMiddleware = true
|
||||
|
||||
var middlewareCalled bool
|
||||
middleware := func(c *Context) {
|
||||
middlewareCalled = true
|
||||
c.Next()
|
||||
}
|
||||
noMethodHandler := func(c *Context) {
|
||||
c.String(http.StatusMethodNotAllowed, "method not allowed")
|
||||
}
|
||||
|
||||
g.Use(middleware)
|
||||
g.NoMethod(noMethodHandler)
|
||||
g.POST("/test", func(c *Context) {
|
||||
c.String(http.StatusOK, "ok")
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest(http.MethodGet, "/test", nil)
|
||||
g.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||
assert.Equal(t, "method not allowed", w.Body.String())
|
||||
assert.False(t, middlewareCalled, "middleware should not be called when SkipMethodNotAllowedMiddleware is true")
|
||||
}
|
||||
|
||||
func TestSkipMethodNotAllowedMiddlewareDisabled(t *testing.T) {
|
||||
g := New()
|
||||
g.HandleMethodNotAllowed = true
|
||||
g.SkipMethodNotAllowedMiddleware = false
|
||||
|
||||
var middlewareCalled bool
|
||||
middleware := func(c *Context) {
|
||||
middlewareCalled = true
|
||||
c.Next()
|
||||
}
|
||||
noMethodHandler := func(c *Context) {
|
||||
c.String(http.StatusMethodNotAllowed, "method not allowed")
|
||||
}
|
||||
|
||||
g.Use(middleware)
|
||||
g.NoMethod(noMethodHandler)
|
||||
g.POST("/test", func(c *Context) {
|
||||
c.String(http.StatusOK, "ok")
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest(http.MethodGet, "/test", nil)
|
||||
g.ServeHTTP(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||
assert.Equal(t, "method not allowed", w.Body.String())
|
||||
assert.True(t, middlewareCalled, "middleware should be called when SkipMethodNotAllowedMiddleware is false")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user