'Gorilla/mux middleware next.ServeHTTP panic
I'm having difficulty wrapping my head around a custom handler using gorilla/mux. It's actually working as intended, but fails at the very last step of calling next.ServeHTTP(r, w)
I start an http server, and attach middleware:
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func NewServer() (*Server, error) {
s := &Server{
// some struct ..
}
r := mux.NewRouter()
// Route all requests to /api3
r.PathPrefix("/api3")
r.Methods("GET", "POST", "PUT", "DELETE")
// Attach middleware, log a thing for each request.
r.Use(LoggingMiddleware)
// .. Some user endpoints
r.Handle("/users", api3.PostUser()).Methods(http.MethodPost)
// Bind to a port and pass our router in
err := http.ListenAndServe(":8080", r)
if err != nil {
// handle error..
}
return s, nil
}
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("LOGGING MIDDLEWARE")
next.ServeHTTP(w, r) <-- panics every time
})
}
What's strange is that the above will print LOGGING MIDDLEWARE but promptly panics thereafter, referring to the next.ServeHTTP(w, r) line.
This example is almost a 1:1 example of Gorilla/mux's own middleware examples.
I've attempted to attach the middleware at the end of the of the function, before calling http.ListenAndServe, thinking order was an issue. It did not work: The same result appears
PostUser looks like:
func PostUser() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var req AddUserRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
err = userDb.Add()
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusOK)
return
})
}
I suspected the PostUser() endpoint might be the culprit. However, removing everything and having a basic endpoint still reproduces the error, example:
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func NewServer() (*Server, error) {
s := &Server{
// some struct ..
}
r := mux.NewRouter()
// Route all requests to /api3
r.PathPrefix("/api3")
r.Methods("GET", "POST", "PUT", "DELETE")
// Attach middleware, log a thing for each request.
r.Use(LoggingMiddleware)
// health endpoint
r.HandleFunc("/health", api3.Health)
// Bind to a port and pass our router in
err := http.ListenAndServe(":8080", r)
if err != nil {
// handle error..
}
return s, nil
}
// Health returns 200 OK if everything is normal
func Health(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprint(w, "OK")
}
The above results in the same. I.e:
curl http://localhost:8081/api3/health
curl: (52) Empty reply from server
With a stacktrace as such:
backend-api | LOGGING MIDDLEWARE <nil>
backend-api | 2022/02/15 15:55:22 http: panic serving 192.168.80.1:59370: runtime error: invalid memory address or nil pointer dereference
backend-api | goroutine 14 [running]:
backend-api | net/http.(*conn).serve.func1(0xc0001dc0a0)
backend-api | /usr/local/go/src/net/http/server.go:1805 +0x153
backend-api | panic(0x8bb2e0, 0xc40c70)
backend-api | /usr/local/go/src/runtime/panic.go:971 +0x499
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
