Go 语言入门教程
net/http 基础
本教程共 80 篇 · 第 76 篇 · 更新于 2026-07-27 · 约 8 分钟阅读
GoGo 入门教程net/httpHTTPHandleFuncListenAndServeHandlerServeMux
76. net/http 基础
本节目标:学会用标准库搭 HTTP 服务、发 HTTP 请求,理解 Handler 接口和路由分发。
最简 HTTP 服务
Go 标准库写 HTTP 服务极简,几行就能跑:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
})
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "API 响应")
})
fmt.Println("服务启动在 :8080")
http.ListenAndServe(":8080", nil)
}
访问 http://localhost:8080 就能看到 Hello, World!。
HandleFunc注册路由ListenAndServe启动服务监听端口- 第二个参数传
nil表示用默认的DefaultServeMux
Handler 接口
http.Handler 是一个接口:
type Handler interface {
ServeHTTP(w ResponseWriter, r *Request)
}
任何实现了 ServeHTTP 方法的类型都能当 Handler。HandleFunc 其实是把普通函数适配成 Handler:
// 这两种写法等价
http.HandleFunc("/", myHandler)
type myHandler struct{}
func (h myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "hello")
}
http.Handle("/", myHandler{})
读取请求信息
*http.Request 包含请求的所有信息:
func handler(w http.ResponseWriter, r *http.Request) {
// 方法
method := r.Method // GET, POST 等
// 路径
path := r.URL.Path
// 查询参数
name := r.URL.Query().Get("name")
// 请求头
contentType := r.Header.Get("Content-Type")
// 请求体(POST 等)
body, _ := io.ReadAll(r.Body)
defer r.Body.Close()
// 路径参数(Go 1.22+ ServeMux 支持)
// http.HandleFunc("/users/{id}", handler)
// id := r.PathValue("id")
fmt.Fprintf(w, "method=%s path=%s name=%s", method, path, name)
}
Go 1.22 增强路由
Go 1.22 的 ServeMux 支持路径参数和方法匹配:
mux := http.NewServeMux()
// 匹配 GET /users/123
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Fprintf(w, "用户 %s", id)
})
// 匹配 POST /users
mux.HandleFunc("POST /users", func(w http.ResponseWriter, r *http.Request) {
// 创建用户
})
http.ListenAndServe(":8080", mux)
以前要靠第三方框架(Gin、Echo)才有的功能,现在标准库自带了。
写响应
func handler(w http.ResponseWriter, r *http.Request) {
// 设置状态码
w.WriteHeader(http.StatusOK) // 200
// 设置响应头
w.Header().Set("Content-Type", "application/json")
// 写响应体
w.Write([]byte(`{"msg":"hello"}`))
}
Warning
WriteHeader必须在Write之前调用。调了Write后再设状态码无效,默认就是 200。
返回 JSON
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
}
func handler(w http.ResponseWriter, r *http.Request) {
resp := Response{Code: 200, Msg: "success"}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp) // 直接编码到 ResponseWriter
}
http.Client 发请求
发 HTTP 请求用 http.Client:
func main() {
// 简单 GET
resp, err := http.Get("https://httpbin.org/get")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
fmt.Println("状态码:", resp.StatusCode)
}
需要更多控制时用 http.NewRequest:
// POST 请求带 JSON body
reqBody := strings.NewReader(`{"name":"Tom"}`)
resp, err := http.Post("https://httpbin.org/post", "application/json", reqBody)
// 自定义请求
req, _ := http.NewRequest("GET", "https://httpbin.org/get", nil)
req.Header.Set("Authorization", "Bearer mytoken")
req.Header.Set("X-Custom", "hello")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
Tip生产环境别用
http.Get(它用默认 Client,没超时)。一定要自己建 Client 并设 Timeout,否则请求卡住会拖垮服务:
client := &http.Client{
Timeout: 30 * time.Second,
}
带 context 的请求
长请求要能取消,用 NewRequestWithContext:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", "https://httpbin.org/delay/10", nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println("超时或出错:", err)
}
5 秒没返回自动取消,不会傻等。
静态文件服务
// 暴露 ./static 目录
fs := http.FileServer(http.Dir("./static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
访问 http://localhost:8080/static/logo.png 就能拿到 ./static/logo.png。
优雅关闭
生产服务要能优雅关闭(处理完现有请求再退出):
srv := &http.Server{Addr: ":8080", Handler: mux}
go func() {
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}()
// 等待中断信号
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
<-stop
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx) // 等现有请求处理完
小结
HandleFunc注册路由,ListenAndServe启动服务- Handler 接口只需实现
ServeHTTP方法 r.URL.Query()取查询参数,r.Body读请求体- Go 1.22
ServeMux支持路径参数和方法匹配 http.Client发请求,务必设 Timeout- 用
NewRequestWithContext实现超时取消 - 生产环境用
Server.Shutdown优雅关闭
下一节讲 flag 命令行解析和 log/slog 日志。