Go 1.22新高级路由下GET /users/register处理器无法访问的问题
问题分析:Go 1.22中访问GET "/users/register"返回404的原因及解决办法
你在试用Go 1.22新特性时,访问GET "/users/register"始终返回404,无法触发对应的处理器函数。相关代码如下:
主包代码
func main() { if err := godotenv.Load(); err != nil { log.Fatal("Failed to load .env:", err) } _, err := repository.InitDB() if err != nil { log.Fatal("Failed to initialise the database:", err) } userMux := http.NewServeMux() if err := handlers.InitUserRoutes(userMux); err != nil { log.Fatal("Failed to initialise user routes:", err) } mux := http.NewServeMux() mux.Handle("/users/", userMux) log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%s", os.Getenv("DOMAIN"), os.Getenv("PORT")), mux)) }
handlers包代码
var templates *template.Template func InitUserRoutes(mux *http.ServeMux) error { var err error templates, err = utils.ParseTemplates("web/templates/user") if err != nil { return err } mux.HandleFunc("GET /register/", registerGet) mux.HandleFunc("POST /register/", registerPost) return nil } func registerGet(w http.ResponseWriter, r *http.Request) { fmt.Println("I'm here") err := templates.ExecuteTemplate(w, "register.html", nil) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func registerPost(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } fmt.Printf("%#v\n\n%#v", r.Form, r.PostForm) email, username, password := r.FormValue("email"), r.FormValue("username"), r.FormValue("password") fmt.Printf("%v, %v, %v\n", email, username, password) }
utils包代码
func ParseTemplates(folderPath string) (*template.Template, error) { return template.ParseGlob(filepath.Join(folderPath, "*.html")) }
问题根源
问题出在路由路径的尾斜杠匹配不一致:
- 主
ServeMux将"/users/"路径挂载到userMux,当请求"/users/register"时,userMux接收到的路径是去掉前缀后的"/register"。 - 但你在
userMux中注册的路由是"GET /register/"(带尾斜杠),和实际传入的"/register"(不带尾斜杠)不匹配,因此返回404。
Go 1.22的ServeMux在子路由挂载场景下,不会自动将不带尾斜杠的路径重定向到带尾斜杠的版本,也不会模糊匹配尾斜杠。
解决办法
有两种简单的修复方式:
方式一:修改子路由的路径,去掉尾斜杠
将handlers包中的路由注册代码改为:mux.HandleFunc("GET /register", registerGet) mux.HandleFunc("POST /register", registerPost)这样
userMux就能匹配到"/register"路径,对应请求"/users/register"即可触发处理器。方式二:调整主路由的挂载路径(可选)
如果你希望保留子路由的尾斜杠,可以将主ServeMux的挂载路径改为"/users"(不带尾斜杠),同时让用户访问"/users/register/"(带尾斜杠)。但这种方式需要前端请求路径同步修改,不如方式一灵活。
内容的提问来源于stack exchange,提问作者Recovery Email
相关产品推荐
相关产品推荐

