Hello,

I'm encountering unexpected behavior with net/http routing in Go 1.24.1 
(amd64, ubuntu linux) when using http.StripPrefix to delegate to a nested 
http.ServeMux which uses the Go 1.22+ METHOD /path routing syntax.

Instead of the nested ServeMux executing its registered handlers for the 
stripped path, it consistently returns a 301 Moved Permanently redirect to 
the stripped path itself.

```go
package main

import (
"fmt"
"log"
"net/http"
"runtime"
)

func handleInnerTest(w http.ResponseWriter, r *http.Request) {
log.Printf("HANDLER HIT: handleInnerTest (GET /test) | Received Path: 
%s\n", r.URL.Path)
fmt.Fprintln(w, "OK - GET /test")
}

func handleInnerLogin(w http.ResponseWriter, r *http.Request) {
log.Printf("HANDLER HIT: handleInnerLogin (POST /login) | Received Path: 
%s\n", r.URL.Path)
if r.Method != http.MethodPost {
http.Error(w, "Method Not Allowed (Handler expected POST)", 
http.StatusMethodNotAllowed)
return
}
fmt.Fprintln(w, "OK - POST /login")
}

func main() {
log.Printf("Go Version: %s\n", runtime.Version())

innerMux := http.NewServeMux()
innerMux.HandleFunc("GET /test", handleInnerTest)
innerMux.HandleFunc("POST /login", handleInnerLogin)
innerMux.HandleFunc("GET /api2/test2", handleInnerTest)

outerMux := http.NewServeMux()

// This should remove "/api/" before innerMux sees the request.
outerMux.Handle("/api/", http.StripPrefix("/api/", innerMux))

outerMux.Handle("/api2/", innerMux)

outerMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
log.Printf("HANDLER HIT: Outer Root Handler | Received Path: %s\n", 
r.URL.Path)
http.NotFound(w, r)
})

port := ":8090"
log.Printf("Starting server on %s...\n", port)
log.Println("----\nEXPECTED BEHAVIOR:")
log.Println("  GET /api/test       -> 200 OK ('OK - GET /test')")
log.Println("  GET /api/nonexistent -> 404 Not Found (from innerMux)")
log.Println("  POST /api/login      -> 200 OK ('OK - POST /login')")
log.Println("----")
log.Println("Run tests like:")
log.Println("  curl -v http://localhost:8090/api/test";)          // is 
HTTP/1.1 301 Moved Permanently && no log print
log.Println("  curl -v http://localhost:8090/api/nonexistent";)   // is 
HTTP/1.1 301 Moved Permanently && no log print
log.Println("  curl -v -X POST http://localhost:8090/api/login";) // is 
HTTP/1.1 301 Moved Permanently && no log print
log.Println("  curl -v http://localhost:8090/test/";)             // is 
HTTP/1.1 404 Not Found && prints HANDLER HIT: Outer Root Handler | Received 
Path: /test/
log.Println("  curl -v http://localhost:8090/api2/test2";)        // is 
HTTP/1.1 200 OK && prints HANDLER HIT: handleInnerTest (GET /test) | 
Received Path: /api2/test2

log.Println("----")

err := http.ListenAndServe(port, outerMux)
if err != nil {
log.Fatalf("Server failed: %v\n", err)
}
}
```

It seems counter-intuitive that after http.StripPrefix modifies the path, 
the inner ServeMux doesn't seem to use that stripped path to match its 
handlers, instead issuing a redirect, like curl -v 
http://localhost:8090/api/test -> `<a href="/test">Moved Permanently</a>`

Have I misunderstood how these components should interact? 

Thanks for any insights.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/cbd4f731-8bcb-4683-8f81-115bb8e4f1a7n%40googlegroups.com.

Reply via email to