使用 Go 1.22 和 http.ServeMux 构建 REST API | 作者: Shiju Varghese

作者:API传播员 · 2026-01-14 · 阅读时间:6分钟
Go 1.22 引入 http.ServeMux 支持 HTTP 方法映射 URI 模式,实现 RESTful API 路由配置,包括使用 Handle 和 HandleFunc 方法、PathValue 获取路由参数,以及创建 HTTP 服务器和处理程序函数,帮助开发者构建功能完善的 REST API。

使用 Go 1.22 和 http.ServeMux 构建 REST API

Go 1.22 引入了一个重要的新功能:http.ServeMux 现在支持通过 HTTP 方法映射 URI 模式。这一功能的实现并未对 ServeMux 类型的现有 API 造成任何破坏性更改。HandleHandleFunc 方法的模式参数格式如下:

[METHOD ][HOST]/[PATH]

其中,METHODHOSTPATH 都是可选的。如果指定了 HTTP 方法,则必须在方法名后加一个空格。以下是一个简单的示例:

使用 ServeMux 映射 URI 模式

mux := http.NewServeMux()
mux.HandleFunc("GET /api/notes", GetAll)
mux.HandleFunc("POST /api/notes", Post)

在上述代码中,GETPOST 是 HTTP 谓词,分别用于处理 /api/notes 路径的 GET 和 POST 请求。如果未指定 HTTP 方法,仍然可以正常工作。


配置 ServeMux 路由器模式

以下代码展示了如何使用 HTTP 方法配置 ServeMux 路由器模式:

func initializeRoutes(h *apphttp.NoteHandler) *http.ServeMux {
    mux := http.NewServeMux()
    mux.HandleFunc("GET /api/notes", h.GetAll)
    mux.HandleFunc("GET /api/notes/{id}", h.Get)
    mux.HandleFunc("POST /api/notes", h.Post)
    mux.HandleFunc("PUT /api/notes/{id}", h.Put)
    mux.HandleFunc("DELETE /api/notes/{id}", h.Delete)
    return mux
}

在上述代码中,不同的 HTTP 方法(如 GET、POST、PUT 和 DELETE)被映射到不同的 URI 模式。通过这种方式,可以轻松实现 RESTful API 的路由配置。


获取路由参数

ServeMux 提供了一个名为 PathValue 的方法,用于从请求中检索命名路径参数的值。例如,以下代码展示了如何获取名为 id 的路由参数:

// 获取路由参数 id
id := r.PathValue("id")

如果请求的路径与模式不匹配,或者模式中没有指定的通配符参数,PathValue 将返回空字符串。


创建 HTTP 服务器

以下代码展示了如何在 package main 中创建一个 HTTP 服务器,并配置路由:

package main

import (
    "log"
    "net/http"    apphttp "github.com/shijuvar/gokit/examples/http-api/httpmux"
    "github.com/shijuvar/gokit/examples/http-api/memstore"
)// 程序入口
func main() {
    repo, err := memstore.NewInmemoryRepository() // 使用内存数据库
    if err != nil {
        log.Fatal("Error:", err)
    }
    h := &apphttp.NoteHandler{
        Repository: repo, // 注入依赖
    }
    router := initializeRoutes(h) // 配置路由    server := &http.Server{
        Addr:    ":8080",
        Handler: router,
    }
    log.Println("Listening...")
    server.ListenAndServe() // 启动 HTTP 服务器
}func initializeRoutes(h *apphttp.NoteHandler) *http.ServeMux {
    mux := http.NewServeMux()
    mux.HandleFunc("GET /api/notes", h.GetAll)
    mux.HandleFunc("GET /api/notes/{id}", h.Get)
    mux.HandleFunc("POST /api/notes", h.Post)
    mux.HandleFunc("PUT /api/notes/{id}", h.Put)
    mux.HandleFunc("DELETE /api/notes/{id}", h.Delete)
    return mux
}

HTTP 处理程序函数

以下代码定义了用于处理 Note 实体 CRUD 操作的 HTTP 处理程序函数:

// Delete 处理 HTTP DELETE 请求 – /api/notes/{id}
func (h NoteHandler) Delete(w http.ResponseWriter, r http.Request) {
id := r.PathValue("id")
if err := h.Repository.Delete(id); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}

import (
"encoding/json"
"errors"
"net/http"

"github.com/shijuvar/gokit/examples/http-api/model"
)

// NoteHandler 组织了 Note 实体的 [CRUD](https://www.explinks.com/wiki/what-is-crud/) 操作 HTTP 处理函数
type NoteHandler struct {
Repository model.Repository // 持久化接口
}

// Post 处理 HTTP POST 请求 - /api/notes
func (h *NoteHandler) Post(w http.ResponseWriter, r *http.Request) {
var note model.Note
// 解码传入的 JSON 数据
err := json.NewDecoder(r.Body).Decode(&note)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// 创建 Note
if err := h.Repository.Create(note); err != nil {
if errors.Is(err, model.ErrNoteExists) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusCreated)
}

// GetAll 处理 HTTP GET 请求 - /api/notes
func (h *NoteHandler) GetAll(w http.ResponseWriter, r *http.Request) {
// 获取所有 Notes
if notes, err := h.Repository.GetAll(); err != nil {
if errors.Is(err, model.ErrNotFound) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} else {
j, err := json.Marshal(notes)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(j)
}
}

// Get 处理 HTTP GET 请求 - /api/notes/{id}
func (h *NoteHandler) Get(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if note, err := h.Repository.GetById(id); err != nil {
if errors.Is(err, model.ErrNotFound) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} else {
w.Header().Set("Content-Type", "application/json")
j, err := json.Marshal(note)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
w.WriteHeader(http.StatusOK)
w.Write(j)
}
}

// Put 处理 HTTP PUT 请求 - /api/notes/{id}
func (h *NoteHandler) Put(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
var note model.Note
err := json.NewDecoder(r.Body).Decode(&note)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := h.Repository.Update(id, note); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}

// Delete 处理 HTTP DELETE 请求 - /api/notes/{id}
func (h *NoteHandler) Delete(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if err := h.Repository.Delete(id); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}

通过以上代码示例,您可以轻松使用 Go 1.22 和 http.ServeMux 构建一个功能完善的 REST API。新版本的 ServeMux 提供了更灵活的路由配置方式,同时保持了简单易用的特点。

原文链接: https://shijuvar.medium.com/building-rest-apis-with-go-1-22-http-servemux-2115f242f02b