大猩猩/ mux中间件中的下一个处理程序为空。

huangapple go评论85阅读模式
英文:

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 错误,和平与爱。

再次感谢大家 大猩猩/ mux中间件中的下一个处理程序为空。

英文:

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 大猩猩/ mux中间件中的下一个处理程序为空。

huangapple
  • 本文由 发表于 2021年9月13日 13:57:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/69157920.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定