go 中用 net/http 创建 HTTP 服务器无需第三方框架,核心是 http.ServeMux 和 Handler;支持默认多路复用器、自定义路由、方法判断、jsON 响应、参数解析及日志/恢复中间件。

在 Go 中用 net/http 创建 HTTP 服务器非常简洁,不需要第三方框架也能轻松处理路由和响应。核心在于理解 http.ServeMux(多路复用器)的作用,以及如何通过 http.HandleFunc 或自定义 http.Handler 来分发请求。
基础 HTTP 服务器:监听与响应
最简服务只需几行代码:
启动一个监听 8080 端口的服务器,对根路径 / 返回纯文本响应:
package main import ( "fmt" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello, World!") }) fmt.Println("Server starting on :8080") http.ListenAndServe(":8080", nil) }
这里 nil 表示使用默认的 http.DefaultServeMux,它负责把请求路径映射到对应的处理函数。
立即学习“go语言免费学习笔记(深入)”;
手动管理路由:使用自定义 ServeMux
显式创建 http.ServeMux 更清晰,也便于测试和复用:
- 避免污染全局默认多路复用器
- 可为不同子服务配置独立路由树
- 方便注入中间件或统一日志
示例:
func main() { mux := http.NewServeMux() mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") fmt.Fprint(w, `{"users":[]}`) }) mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) fmt.Fprint(w, "OK") }) http.ListenAndServe(":8080", mux) }
支持不同 HTTP 方法:检查 r.Method
net/http 不直接按方法(GET/POST/PUT)自动路由,需在 handler 内判断:
mux.HandleFunc("/posts", func(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": // 返回文章列表 w.Header().Set("Content-Type", "application/json") fmt.Fprint(w, `[{"id":1,"title":"Go入门"}]`) case "POST": // 创建新文章 w.WriteHeader(http.StatusCreated) fmt.Fprint(w, `{"id":2,"title":"新文章"}`) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } })
注意:确保返回正确状态码和响应头,尤其是 JSON 接口要设 Content-Type: application/json。
返回结构化数据:JSON 响应
用 json.Marshal 序列化结构体,并设置响应头:
type User struct { ID int `json:"id"` Name string `json:"name"` } mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) { user := User{ID: 123, Name: "Alice"} w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(user) // 自动调用 Marshal,更安全 })
推荐用 json.NewEncoder(w).Encode() 替代 json.Marshal() + fmt.Fprint,它能流式写入、避免内存拷贝,且自动处理错误(如编码失败时写入空响应)。
处理 URL 参数和表单数据
查询参数(?key=value):r.URL.Query().Get("page")
路径参数(需手动解析,如 /user/123):用 strings.Split(r.URL.Path, "/") 或正则提取
表单数据(POST 表单或 x-www-form-urlencoded):r.ParseForm() 后读 r.FormValue("username")
JSON 请求体:用 io.ReadAll(r.Body) 读取原始字节,再 json.Unmarshal
示例(读取 JSON 请求体):
mux.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "POST required", http.StatusMethodNotAllowed) return } var req struct { Username string `json:"username"` Password string `json:"password"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid JSON", http.StatusbadRequest) return } // 验证逻辑... w.Header().Set("Content-Type", "application/json") fmt.Fprint(w, `{"success":true}`) })
添加简单中间件:日志与恢复
通过包装 handler 实现通用逻辑:
func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Printf("→ %s %sn", r.Method, r.URL.Path) next.ServeHTTP(w, r) }) } func recoverMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { http.Error(w, "Internal error", http.StatusInternalServerError) fmt.Printf("Panic: %vn", err) } }() next.ServeHTTP(w, r) }) } // 使用: mux := http.NewServeMux() mux.HandleFunc("/api/", apiHandler) http.ListenAndServe(":8080", recoverMiddleware(loggingMiddleware(mux)))
注意中间件顺序:越靠外的越先执行(如日志在 recover 外层,就能记录 panic 前的请求)。