Go net/http 标准库基础一、知识点总结1.1 net/http 包的设计理念Go 的net/http包是标准库中最具代表性的设计之一它遵循接口驱动的设计哲学。整个包围绕两个核心接口展开Handler接口处理 HTTP 请求的核心抽象ResponseWriter*Request请求-响应的载体这种设计的精妙之处在于解耦。你可以用任何自定义类型实现Handler接口然后注册到服务端不需要继承任何类或框架提供的基类。这是 Go “接口即契约” 思想的典型体现。1.2 Handler 接口typeHandlerinterface{ServeHTTP(w ResponseWriter,r*Request)}任何实现了ServeHTTP方法的类型都可以作为 HTTP 处理器。标准库提供了HandlerFunc类型作为函数适配器让普通函数也能当作 Handler 使用typeHandlerFuncfunc(ResponseWriter,*Request)func(f HandlerFunc)ServeHTTP(w ResponseWriter,r*Request){f(w,r)}这个技巧非常经典——它让函数和实现了接口的结构体可以互换使用既保留了接口的扩展性又提供了函数的便利性。1.3 ServeMux —— 路由多路复用器ServeMux是标准库内置的路由分发器负责将 URL 匹配到对应的 Handler注册路由mux.Handle(/path, handler)或mux.HandleFunc(/path, fn)匹配规则最长前缀匹配例如/api/users比/api/更优先路径规范会自动处理冗余斜杠//→/区分大小写URL 路径匹配是大小写敏感的1.4 Server 结构体与 ListenAndServehttp.Server是一个可配置的服务端结构体typeServerstruct{Addrstring// 监听地址如 :8080Handler Handler// 若nil则使用 DefaultServeMuxReadTimeout time.Duration// 读取请求超时WriteTimeout time.Duration// 写入响应超时IdleTimeout time.Duration// Keep-Alive 连接空闲超时MaxHeaderBytesint// 请求头最大字节数}http.ListenAndServe是快捷函数内部创建一个默认的 Server。生产环境建议显式配置Server以便控制超时行为——没有超时的服务是生产事故的温床。1.5 ResponseWriter 与 RequestResponseWriter用于构造响应WriteHeader(statusCode)—— 写入状态码只能调用一次且必须在 Write 之前Write([]byte)—— 写入响应体若未调用 WriteHeader自动写入 200 OKHeader()—— 获取响应头http.Header必须在 WriteHeader 前设置Request封装了请求的所有信息r.Method—— HTTP 方法GET/POST/PUT/DELETE 等r.URL—— 解析后的 URL 对象含 Path、RawQuery、Scheme 等r.Header—— 请求头r.Body—— 请求体io.ReadCloser必须关闭r.FormValue(key)—— 获取表单值自动解析 query string 和 POST body1.6 重要注意事项WriteHeader 只能调用一次重复调用会触发 panic 或无效Header 必须在 WriteHeader 前设置否则不生效请求体必须关闭defer r.Body.Close()否则连接池会泄漏没有路由参数标准库 ServeMux 不支持/users/:id这种路由参数需要手动从r.URL.Path解析或使用第三方框架默认无超时ListenAndServe没有配置任何超时生产环境必须显式设置二、练习代码示例 1最基础的 HTTP 服务packagemainimport(fmtlognet/http)funcmain(){// 使用 HandleFunc 注册路由底层自动包装为 HandlerFunchttp.HandleFunc(/,func(w http.ResponseWriter,r*http.Request){fmt.Fprintf(w,Hello, Go HTTP! Method%s, Path%s\n,r.Method,r.URL.Path)})http.HandleFunc(/health,func(w http.ResponseWriter,r*http.Request){w.WriteHeader(http.StatusOK)fmt.Fprintln(w,{status:ok})})log.Println(Server starting on :8080)// 等价于 http.ListenAndServe(:8080, nil)// nil 表示使用 DefaultServeMuxiferr:http.ListenAndServe(:8080,nil);err!nil{log.Fatal(err)}}示例 2自定义 Handler 结构体packagemainimport(fmtlognet/httpsync/atomic)// CounterHandler 是一个自定义 Handler统计访问次数typeCounterHandlerstruct{count atomic.Int64}func(h*CounterHandler)ServeHTTP(w http.ResponseWriter,r*http.Request){// 原子递增线程安全c:h.count.Add(1)w.Header().Set(Content-Type,text/plain; charsetutf-8)fmt.Fprintf(w,你是第 %d 位访客\n,c)}funcmain(){mux:http.NewServeMux()counter:CounterHandler{}// 注册自定义 Handlermux.Handle(/counter,counter)mux.HandleFunc(/,func(w http.ResponseWriter,r*http.Request){fmt.Fprintln(w,访问 /counter 查看计数)})log.Println(Server on :8080)iferr:http.ListenAndServe(:8080,mux);err!nil{log.Fatal(err)}}示例 3带超时的生产级 Server 配置packagemainimport(contextfmtlognet/httposos/signalsyscalltime)funcmain(){mux:http.NewServeMux()mux.HandleFunc(/,func(w http.ResponseWriter,r*http.Request){fmt.Fprintln(w,Hello with timeout protection!)})mux.HandleFunc(/slow,func(w http.ResponseWriter,r*http.Request){// 模拟慢请求5秒延迟time.Sleep(5*time.Second)fmt.Fprintln(w,slow response)})// 生产环境推荐显式配置 Server设置超时server:http.Server{Addr::8080,Handler:mux,ReadTimeout:3*time.Second,// 读取完整请求的最大时间WriteTimeout:5*time.Second,// 写入响应的最大时间IdleTimeout:60*time.Second,// Keep-Alive 空闲超时}// 优雅关闭在独立 goroutine 中启动服务gofunc(){log.Println(Server starting on :8080)iferr:server.ListenAndServe();err!nilerr!http.ErrServerClosed{log.Fatalf(Server error: %v,err)}}()// 监听系统信号实现优雅关闭sigChan:make(chanos.Signal,1)signal.Notify(sigChan,syscall.SIGINT,syscall.SIGTERM)-sigChan log.Println(Shutting down server...)// 给正在处理的请求 5 秒缓冲时间ctx,cancel:context.WithTimeout(context.Background(),5*time.Second)defercancel()iferr:server.Shutdown(ctx);err!nil{log.Fatalf(Shutdown error: %v,err)}log.Println(Server gracefully stopped)}示例 4ResponseWriter 使用要点演示packagemainimport(fmtlognet/http)funcmain(){mux:http.NewServeMux()// 正确设置 Header 的顺序演示mux.HandleFunc(/headers,func(w http.ResponseWriter,r*http.Request){// 1. 先设置响应头w.Header().Set(Content-Type,application/json)w.Header().Set(X-Custom-Header,myvalue)// 2. 再调用 WriteHeader可选Write 会自动调w.WriteHeader(http.StatusCreated)// 201// 3. 最后写入响应体fmt.Fprintln(w,{message:created})// 下面这行无效WriteHeader 已调用再设置 Header 不生效w.Header().Set(X-Late-Header,too-late)})// 演示请求信息读取mux.HandleFunc(/info,func(w http.ResponseWriter,r*http.Request){w.Header().Set(Content-Type,text/plain)fmt.Fprintf(w,Method: %s\n,r.Method)fmt.Fprintf(w,URL Path: %s\n,r.URL.Path)fmt.Fprintf(w,Query: %s\n,r.URL.RawQuery)fmt.Fprintf(w,User-Agent: %s\n,r.UserAgent())fmt.Fprintf(w,Host: %s\n,r.Host)fmt.Fprintf(w,RemoteAddr: %s\n,r.RemoteAddr)})log.Println(Server on :8080)log.Fatal(http.ListenAndServe(:8080,mux))}