中间件中的 gorilla/mux 下一个处理程序是 nil
Posted
技术标签:
【中文标题】中间件中的 gorilla/mux 下一个处理程序是 nil【英文标题】:gorilla/mux next handler in middleware is nil 【发布时间】:2021-09-13 05:57:35 【问题描述】:我有一个自定义的中间件,我给中间件传递了一个参数,但是当我启动服务器时,我得到了一个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 中间件:
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 := &servicegrpcService: 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
测试:
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
我真的很困惑为什么下一个处理程序是 nil ..
因为它是nil
,我的路由器的下一个处理程序将永远不会被执行,包括我真正的处理程序,甚至不是中间件。
如果我有什么问题?我想不通。
【问题讨论】:
请勿发布文字图片。 请以文字形式分享minimal reproducible example。 @JuanChan 你能在60
行显示文件../middleware/inject.go
中的内容吗?
@Volker 我已将图像更改为文本
@mkopriva 我已经更新了这篇文章,并指出了恐慌发生的地方。你会看到next.ServeHTTP(w, r) // next is nil ! panic here
【参考方案1】:
谢谢大家,我已经解决了这个问题。
我使用alice 来包装中间件和我的处理程序:
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
我所做的一件重要的事情是将新多路复用路由器的方式从router := RouterWithPrefix("")
更改为router := mux.NewRouter()
。
这可以避免我的处理程序出现 404。
那么,不再有NPE
,和平与爱。
再次感谢大家:)
【讨论】:
以上是关于中间件中的 gorilla/mux 下一个处理程序是 nil的主要内容,如果未能解决你的问题,请参考以下文章
使用 Gorilla MUX 和 Negroni 子路由中间件