英文:
gorilla/mux next handler in middleware is nil
问题
我有一个自定义的中间件,并且我将一个参数传递给了这个中间件,但是当我启动服务器时,我遇到了一个NPE
(空指针异常):
func SetMigrater(mgt dmigrate.Migrater) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r = httputil.WithValue(r, dmigrate.DockerMigraterKey, mgt)
next.ServeHTTP(w, r) // next 是 nil!在这里发生了 panic。middleware/inject.go:57
})
}
}
RequestID 中间件:
14 func RequestID(next http.Handler) http.Handler {
15 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16 id := uuidutil.GenerateWithoutHyphen()
17 r = r.WithContext(context.WithValue(r.Context(), RequestIdKey, id))
18 w.Header().Add(RequestIdKey, id)
19 next.ServeHTTP(w, r)
20 })
21 }
堆栈跟踪:
2021/09/13 10:39:54 runtime error: invalid memory address or nil pointer dereference
2021/09/13 10:39:54 goroutine 502 [running]:
runtime/debug.Stack(0xc001008aa0, 0x1, 0x1)
/usr/local/go/src/runtime/debug/stack.go:24 +0x9f
github.com/gorilla/handlers.recoveryHandler.log(0x2210e60, 0xc00100e7e0, 0x0, 0x0, 0x1, 0xc001008aa0, 0x1, 0x1)
/app/vendor/github.com/gorilla/handlers/recovery.go:89 +0x7e
github.com/gorilla/handlers.recoveryHandler.ServeHTTP.func1(0x22316e8, 0xc00100b680, 0x2210e60, 0xc00100e7e0, 0x0, 0x0, 0x1)
/app/vendor/github.com/gorilla/handlers/recovery.go:74 +0xe5
panic(0x1b59240, 0x2f8e960)
/usr/local/go/src/runtime/panic.go:965 +0x1b9
.../server/http/handlers/middleware.SetMigrater.func1.1(0x22316e8, 0xc00100b680, 0xc000563300)
.../server/http/handlers/middleware/inject.go:57 +0x83
net/http.HandlerFunc.ServeHTTP(0xc00100e780, 0x22316e8, 0xc00100b680, 0xc000563300)
/usr/local/go/src/net/http/server.go:2069 +0x44
.../server/http/handlers/middleware.SetAmqpMessager.func1.1(0x22316e8, 0xc00100b680, 0xc000563200)
.../server/http/handlers/middleware/inject.go:48 +0xab
net/http.HandlerFunc.ServeHTTP(0xc00100e7b0, 0x22316e8, 0xc00100b680, 0xc000563200)
/usr/local/go/src/net/http/server.go:2069 +0x44
.../server/http/handlers/middleware.SetGrpcService.func1.1(0x22316e8, 0xc00100b680, 0xc000563100)
.../server/http/handlers/middleware/inject.go:39 +0xa2
net/http.HandlerFunc.ServeHTTP(0xc000cd6ec0, 0x22316e8, 0xc00100b680, 0xc000563100)
/usr/local/go/src/net/http/server.go:2069 +0x44
.../server/http/handlers/middleware.SetRegistryClient.func1(0x22316e8, 0xc00100b680, 0xc000563000)
.../server/http/handlers/middleware/inject.go:31 +0x24d
net/http.HandlerFunc.ServeHTTP(0xc000cc5d10, 0x22316e8, 0xc00100b680, 0xc000563000)
/usr/local/go/src/net/http/server.go:2069 +0x44
.../server/http/handlers/middleware.SetDBHandler.func1.1(0x22316e8, 0xc00100b680, 0xc000562f00)
.../server/http/handlers/middleware/inject.go:22 +0xab
net/http.HandlerFunc.ServeHTTP(0xc00100e7e0, 0x22316e8, 0xc00100b680, 0xc000562f00)
/usr/local/go/src/net/http/server.go:2069 +0x44
github.com/gorilla/handlers.recoveryHandler.ServeHTTP(0x2210e60, 0xc00100e7e0, 0x0, 0x0, 0x1, 0x22316e8, 0xc00100b680, 0xc000562f00)
/app/vendor/github.com/gorilla/handlers/recovery.go:78 +0xce
.../server/http/handlers/middleware.RequestID.func1(0x22316e8, 0xc00100b680, 0xc000562e00)
.../server/http/handlers/middleware/request_id.go:19 +0x270
net/http.HandlerFunc.ServeHTTP(0xc000cc5d28, 0x22316e8, 0xc00100b680, 0xc000562e00)
/usr/local/go/src/net/http/server.go:2069 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001db200, 0x22316e8, 0xc00100b680, 0xc000562c00)
/app/vendor/github.com/gorilla/mux/mux.go:210 +0xd3
github.com/felixge/httpsnoop.CaptureMetrics.func1(0x22316e8, 0xc00100b680)
/app/vendor/github.com/felixge/httpsnoop/capture_metrics.go:29 +0x4c
github.com/felixge/httpsnoop.CaptureMetricsFn(0x2230398, 0xc000cce1c0, 0xc000dbd848, 0xc000da7880, 0x203000, 0x7fba9ad1c190)
/app/vendor/github.com/felixge/httpsnoop/capture_metrics.go:76 +0x20a
github.com/felixge/httpsnoop.CaptureMetrics(0x220ab20, 0xc0001db200, 0x2230398, 0xc000cce1c0, 0xc000562c00, 0x7fba9ac341d0, 0x800, 0x5)
/app/vendor/github.com/felixge/httpsnoop/capture_metrics.go:28 +0x7d
e.coding.net/codingcorp/coding-artifacts/internal/server/docker_core/server/http/handlers/middleware.Logging.func1(0x2230398, 0xc000cce1c0, 0xc000562c00)
/app/internal/server/docker_core/server/http/handlers/middleware/logging.go:15 +0x6f
net/http.HandlerFunc.ServeHTTP(0xc000ece960, 0x2230398, 0xc000cce1c0, 0xc000562c00)
/usr/local/go/src/net/http/server.go:2069 +0x44
net/http.serverHandler.ServeHTTP(0xc0006582a0, 0x2230398, 0xc000cce1c0, 0xc000562c00)
/usr/local/go/src/net/http/server.go:2887 +0xa3
net/http.(*conn).serve(0xc000dac780, 0x2239e70, 0xc000cdbd00)
/usr/local/go/src/net/http/server.go:1952 +0x8cd
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:3013 +0x39b
中间件:
func (app *App) useMiddlewares() {
app.router.Use(middleware.RequestID)
app.router.Use(handlers.RecoveryHandler(handlers.PrintRecoveryStack(true)))
app.router.Use(
middleware.SetDBHandler(app.db),
middleware.SetRegistryClient,
middleware.SetGrpcService(app.grpcService),
)
app.router.Use(middleware.SetAmqpMessager(messager))
app.router.Use(middleware.SetMigrater(migrater))
}
更多信息:
新的路由器:
// RouterWithPrefix builds a gorilla router with a configured prefix
// on all routes.
func RouterWithPrefix(prefix string) *mux.Router {
rootRouter := mux.NewRouter()
router := rootRouter
if prefix != "" {
router = router.PathPrefix(prefix).Subrouter()
}
router.StrictSlash(true)
for _, descriptor := range routeDescriptors {
router.Path(descriptor.Path).Name(descriptor.Name)
}
return rootRouter
}
启动这个 HTTP 服务器:
func (app *App) ListenAndServe(port int) error {
svc := &service{grpcService: app.grpcService}
// base
r := app.router.PathPrefix("/v2").Subrouter()
r.Use(
middleware.Whitelist,
middleware.PassInternalRequest,
middleware.Authenticate(app.grpcService),
middleware.SetArtInfo(app.grpcService),
)
// /v2/
r.HandleFunc("/", proxyutil.ServeHTTP).Methods(http.MethodGet)
// 其他处理程序...
loggedHandler := middleware.Logging(app.router)
app.server = &http.Server{
Addr: httputil.Addr(port),
Handler: loggedHandler,
}
log.Info("Serving the HTTP server successfully", zap.Int("port", port))
if err := app.server.ListenAndServe(); err != nil && !errors.IgnoreError(err) {
return err
}
return nil
}
测试:
curl -v http://localhost:8080/v2/
500 Internal Server Error
我的 Go 版本:go version go1.16.5 linux/amd64
gorilla/mux
版本:github.com/gorilla/mux v1.8.0
我真的很困惑为什么这个 next 处理程序是空的..
而且因为它是 nil
,我的路由器的后续处理程序将永远不会被执行,包括我的真正处理程序,甚至是中间件。
如果我有什么错误吗?我无法弄清楚这个问题。
英文:
I have a custom middleware, and I passed a parameter to the middleware, but when I started the server, I got an NPE
:
func SetMigrater(mgt dmigrate.Migrater) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r = httputil.WithValue(r, dmigrate.DockerMigraterKey, mgt)
next.ServeHTTP(w, r) // next is nil ! panic here. middleware/inject.go:57
})
}
}
RequestID middleware:
14 func RequestID(next http.Handler) http.Handler {
15 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16 id := uuidutil.GenerateWithoutHyphen()
17 r = r.WithContext(context.WithValue(r.Context(), RequestIdKey, id))
18 w.Header().Add(RequestIdKey, id)
19 next.ServeHTTP(w, r)
20 })
21 }
Stack trace:
2021/09/13 10:39:54 runtime error: invalid memory address or nil pointer dereference
2021/09/13 10:39:54 goroutine 502 [running]:
runtime/debug.Stack(0xc001008aa0, 0x1, 0x1)
/usr/local/go/src/runtime/debug/stack.go:24 +0x9f
github.com/gorilla/handlers.recoveryHandler.log(0x2210e60, 0xc00100e7e0, 0x0, 0x0, 0x1, 0xc001008aa0, 0x1, 0x1)
/app/vendor/github.com/gorilla/handlers/recovery.go:89 +0x7e
github.com/gorilla/handlers.recoveryHandler.ServeHTTP.func1(0x22316e8, 0xc00100b680, 0x2210e60, 0xc00100e7e0, 0x0, 0x0, 0x1)
/app/vendor/github.com/gorilla/handlers/recovery.go:74 +0xe5
panic(0x1b59240, 0x2f8e960)
/usr/local/go/src/runtime/panic.go:965 +0x1b9
.../server/http/handlers/middleware.SetMigrater.func1.1(0x22316e8, 0xc00100b680, 0xc000563300)
.../server/http/handlers/middleware/inject.go:57 +0x83
net/http.HandlerFunc.ServeHTTP(0xc00100e780, 0x22316e8, 0xc00100b680, 0xc000563300)
/usr/local/go/src/net/http/server.go:2069 +0x44
.../server/http/handlers/middleware.SetAmqpMessager.func1.1(0x22316e8, 0xc00100b680, 0xc000563200)
.../server/http/handlers/middleware/inject.go:48 +0xab
net/http.HandlerFunc.ServeHTTP(0xc00100e7b0, 0x22316e8, 0xc00100b680, 0xc000563200)
/usr/local/go/src/net/http/server.go:2069 +0x44
.../server/http/handlers/middleware.SetGrpcService.func1.1(0x22316e8, 0xc00100b680, 0xc000563100)
.../server/http/handlers/middleware/inject.go:39 +0xa2
net/http.HandlerFunc.ServeHTTP(0xc000cd6ec0, 0x22316e8, 0xc00100b680, 0xc000563100)
/usr/local/go/src/net/http/server.go:2069 +0x44
.../server/http/handlers/middleware.SetRegistryClient.func1(0x22316e8, 0xc00100b680, 0xc000563000)
.../server/http/handlers/middleware/inject.go:31 +0x24d
net/http.HandlerFunc.ServeHTTP(0xc000cc5d10, 0x22316e8, 0xc00100b680, 0xc000563000)
/usr/local/go/src/net/http/server.go:2069 +0x44
.../server/http/handlers/middleware.SetDBHandler.func1.1(0x22316e8, 0xc00100b680, 0xc000562f00)
.../server/http/handlers/middleware/inject.go:22 +0xab
net/http.HandlerFunc.ServeHTTP(0xc00100e7e0, 0x22316e8, 0xc00100b680, 0xc000562f00)
/usr/local/go/src/net/http/server.go:2069 +0x44
github.com/gorilla/handlers.recoveryHandler.ServeHTTP(0x2210e60, 0xc00100e7e0, 0x0, 0x0, 0x1, 0x22316e8, 0xc00100b680, 0xc000562f00)
/app/vendor/github.com/gorilla/handlers/recovery.go:78 +0xce
.../server/http/handlers/middleware.RequestID.func1(0x22316e8, 0xc00100b680, 0xc000562e00)
.../server/http/handlers/middleware/request_id.go:19 +0x270
net/http.HandlerFunc.ServeHTTP(0xc000cc5d28, 0x22316e8, 0xc00100b680, 0xc000562e00)
/usr/local/go/src/net/http/server.go:2069 +0x44
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0001db200, 0x22316e8, 0xc00100b680, 0xc000562c00)
/app/vendor/github.com/gorilla/mux/mux.go:210 +0xd3
github.com/felixge/httpsnoop.CaptureMetrics.func1(0x22316e8, 0xc00100b680)
/app/vendor/github.com/felixge/httpsnoop/capture_metrics.go:29 +0x4c
github.com/felixge/httpsnoop.CaptureMetricsFn(0x2230398, 0xc000cce1c0, 0xc000dbd848, 0xc000da7880, 0x203000, 0x7fba9ad1c190)
/app/vendor/github.com/felixge/httpsnoop/capture_metrics.go:76 +0x20a
github.com/felixge/httpsnoop.CaptureMetrics(0x220ab20, 0xc0001db200, 0x2230398, 0xc000cce1c0, 0xc000562c00, 0x7fba9ac341d0, 0x800, 0x5)
/app/vendor/github.com/felixge/httpsnoop/capture_metrics.go:28 +0x7d
e.coding.net/codingcorp/coding-artifacts/internal/server/docker_core/server/http/handlers/middleware.Logging.func1(0x2230398, 0xc000cce1c0, 0xc000562c00)
/app/internal/server/docker_core/server/http/handlers/middleware/logging.go:15 +0x6f
net/http.HandlerFunc.ServeHTTP(0xc000ece960, 0x2230398, 0xc000cce1c0, 0xc000562c00)
/usr/local/go/src/net/http/server.go:2069 +0x44
net/http.serverHandler.ServeHTTP(0xc0006582a0, 0x2230398, 0xc000cce1c0, 0xc000562c00)
/usr/local/go/src/net/http/server.go:2887 +0xa3
net/http.(*conn).serve(0xc000dac780, 0x2239e70, 0xc000cdbd00)
/usr/local/go/src/net/http/server.go:1952 +0x8cd
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:3013 +0x39b
Middlewares:
func (app *App) useMiddlewares() {
app.router.Use(middleware.RequestID)
app.router.Use(handlers.RecoveryHandler(handlers.PrintRecoveryStack(true)))
app.router.Use(
middleware.SetDBHandler(app.db),
middleware.SetRegistryClient,
middleware.SetGrpcService(app.grpcService),
)
app.router.Use(middleware.SetAmqpMessager(messager))
app.router.Use(middleware.SetMigrater(migrater))
}
More information:
new router:
// RouterWithPrefix builds a gorilla router with a configured prefix
// on all routes.
func RouterWithPrefix(prefix string) *mux.Router {
rootRouter := mux.NewRouter()
router := rootRouter
if prefix != "" {
router = router.PathPrefix(prefix).Subrouter()
}
router.StrictSlash(true)
for _, descriptor := range routeDescriptors {
router.Path(descriptor.Path).Name(descriptor.Name)
}
return rootRouter
}
Serving this http server:
func (app *App) ListenAndServe(port int) error {
svc := &service{grpcService: app.grpcService}
// base
r := app.router.PathPrefix("/v2").Subrouter()
r.Use(
middleware.Whitelist,
middleware.PassInternalRequest,
middleware.Authenticate(app.grpcService),
middleware.SetArtInfo(app.grpcService),
)
// /v2/
r.HandleFunc("/", proxyutil.ServeHTTP).Methods(http.MethodGet)
// other handlers ...
loggedHandler := middleware.Logging(app.router)
app.server = &http.Server{
Addr: httputil.Addr(port),
Handler: loggedHandler,
}
log.Info("Serving the HTTP server successfully", zap.Int("port", port))
if err := app.server.ListenAndServe(); err != nil && !errors.IgnoreError(err) {
return err
}
return nil
}
Test:
curl -v http://localhost:8080/v2/
500 Internal Server Error
My go version: go version go1.16.5 linux/amd64
gorilla/mux
version: github.com/gorilla/mux v1.8.0
I'm really confused why this next handler is nil ..
And because it is nil
, my next handlers of the router will never be execute, include my real handlers, not even middlewares.
If I have something wrong? I couldn't figure this out.
答案1
得分: 1
谢谢大家,我已经解决了这个问题。
我使用 alice 来包装中间件和处理程序:
func (app *App) addMiddlewares() http.Handler {
return alice.New(
middleware.Logging,
middleware.RequestID,
// 其他一些中间件...
middleware.SetMigrater(migrater),
).Then(app.router)
}
func (app *App) ListenAndServe(port int) error {
svc := &service{}
// 基础
r := app.router.PathPrefix("/v2").Subrouter()
r.Use(
middleware.Whitelist,
middleware.PassInternalRequest,
middleware.Authenticate(app.grpcService),
middleware.SetArtInfo(app.grpcService),
)
// /v2/
r.HandleFunc("/", proxyutil.ServeHTTP).Methods(http.MethodGet)
// 包装处理程序
handler := app.addMiddlewares()
app.server = &http.Server{
Addr: httputil.Addr(port),
Handler: handler,
}
log.Info("成功启动HTTP服务器", zap.Int("端口", port))
if err := app.server.ListenAndServe(); err != nil && !errors.IgnoreError(err) {
return err
}
return nil
}
我做的一个重要的改变是将创建 mux 路由器的方式从 router := RouterWithPrefix("")
改为 router := mux.NewRouter()
。
这样可以避免我的处理程序返回 404 错误。
然后,不再出现 NPE
错误,和平与爱。
再次感谢大家
英文:
Thanks all, I've solved this problem.
I use alice to wrap middlewares and my handler:
func (app *App) addMiddlewares() http.Handler {
return alice.New(
middleware.Logging,
middleware.RequestID,
// some other middlewares ...
middleware.SetMigrater(migrater),
).Then(app.router)
}
func (app *App) ListenAndServe(port int) error {
svc := &service{}
// base
r := app.router.PathPrefix("/v2").Subrouter()
r.Use(
middleware.Whitelist,
middleware.PassInternalRequest,
middleware.Authenticate(app.grpcService),
middleware.SetArtInfo(app.grpcService),
)
// /v2/
r.HandleFunc("/", proxyutil.ServeHTTP).Methods(http.MethodGet)
// wrap the handler
handler := app.addMiddlewares()
app.server = &http.Server{
Addr: httputil.Addr(port),
Handler: handler,
}
log.Info("Serving the HTTP server successfully", zap.Int("port", port))
if err := app.server.ListenAndServe(); err != nil && !errors.IgnoreError(err) {
return err
}
return nil
}
And one important thing what I did was change the way to new a mux router from router := RouterWithPrefix("")
to router := mux.NewRouter()
.
This could avoid 404 from my handlers.
Then, no NPE
anymore, peace and love.
Thanks everyone again
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论