You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go net/http嵌套路由无法访问controller问题求助

Go net/http嵌套路由无法匹配Controller的问题排查

问题描述

我通过Go标准库net/http实现嵌套路由,期望所有路由前缀为/api/v1(如/api/v1/tasks、/api/v1/orders),但请求无法到达controller层,访问localhost:8000/api/v1/tasks或localhost:8000/api/v1//tasks均返回"no page found"。完整代码如下:

main.go

package main

import (
    "fmt"
    "net/http"

    "github.com/sayedulkrm/go-curd-todo/routes"
)

func main() {

    taskRouter := routes.TaskRoutes()

    mainRouter := http.NewServeMux()

    mainRouter.Handle("/api/v1/", taskRouter)

    fmt.Printf("Server running on port 8000")

    http.ListenAndServe(":8000", mainRouter)

}

routes/routes.go

package routes

import (
    "fmt"
    "net/http"

    "github.com/sayedulkrm/go-curd-todo/controllers"
)

func TaskRoutes() *http.ServeMux {

    router := http.NewServeMux()

    fmt.Printf("Heyyy Am getting called From TaskRoutes")

    router.HandleFunc("GET /tasks", controllers.GetAllTasks)

    return router

}

controllers/controllers.go

package controllers

import (
    "fmt"
    "net/http"
)

func GetAllTasks(w http.ResponseWriter, r *http.Request) {

    fmt.Printf("Heyyy Am getting called From Controllers")

    w.Write([]byte(`{"message": "working..."}`))

}

问题原因及修复方案

核心问题:子路由路径匹配错误

当你通过mainRouter.Handle("/api/v1/", taskRouter)挂载子路由时,主ServeMux会将匹配到的/api/v1/前缀去除,然后把不带开头斜杠的剩余路径(比如请求/api/v1/tasks时,剩余路径是tasks)传给子ServeMux。但你的子路由定义的是GET /tasks,子ServeMux无法匹配到tasks路径,因此返回404。

此外,Go 1.22之前的标准库ServeMux不支持METHOD /path这种路由语法,这也是可能导致路由失效的原因。


修复步骤

方案一:兼容所有Go版本

  1. 主路由使用http.StripPrefix处理路径
    修改main.go中的挂载逻辑,确保子路由收到带开头斜杠的完整路径:
    mainRouter.Handle("/api/v1/", http.StripPrefix("/api/v1", taskRouter))
    
  2. 子路由内手动校验请求方法
    如果你的Go版本低于1.22,需要在子路由的handler中判断请求方法:
    package routes
    
    import (
        "fmt"
        "net/http"
    
        "github.com/sayedulkrm/go-curd-todo/controllers"
    )
    
    func TaskRoutes() *http.ServeMux {
        router := http.NewServeMux()
        fmt.Println("Heyyy Am getting called From TaskRoutes")
    
        router.HandleFunc("/tasks", func(w http.ResponseWriter, r *http.Request) {
            // 校验请求方法
            if r.Method != http.MethodGet {
                http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
                return
            }
            controllers.GetAllTasks(w, r)
        })
    
        return router
    }
    

方案二:仅适用于Go 1.22+版本

Go 1.22及以后的ServeMux支持METHOD /path的路由语法,只需调整主路由的路径处理:

  1. 主路由添加http.StripPrefix
    同方案一的第一步,修改main.go的挂载代码。
  2. 保留子路由的方法路由定义
    子路由的HandleFunc可以直接使用GET /tasks语法:
    router.HandleFunc("GET /tasks", controllers.GetAllTasks)
    

额外注意事项

  • 避免使用/api/v1//tasks这种双斜杠路径,虽然HTTP规范允许,但建议使用标准路径/api/v1/tasks。
  • 启动服务器后,检查控制台是否输出Heyyy Am getting called From TaskRoutes,确认子路由是否被正确初始化。

内容的提问来源于stack exchange,提问作者Sayedul Karim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 06:00:07