应显式构造 http.ServeMux 或自定义 Handler,避免 http.ListenAndServe(":8080", nil) 引发路由冲突;Addr 必须含端口如 ":8080";r.Body 需 defer 关闭且不可重复读;静态文件用 http.FileServer + http.StripPrefix;HTTP/2 仅在 TLS 下启用。

用 net/http 启动最简 HTTP 服务,别碰 http.ListenAndServe 的默认参数
Go 自带的 net/http 包开箱即用,但直接写 http.ListenAndServe(":8080", nil) 容易踩坑。它会隐式创建一个全局的 http.DefaultServeMux,一旦多个包都调用 http.HandleFunc,路由就可能互相覆盖或冲突——尤其在引入第三方中间件或测试并行运行时。
推荐始终显式构造 http.ServeMux 或自定义 http.Handler:
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Write([]byte("hello"))
})
server := &http.Server{
Addr: ":8080",
Handler: mux,
}
log.Fatal(server.ListenAndServe())
- 避免使用
nil作为Handler,明确控制路由入口 -
Addr字符串必须含端口(如":8080"),不能只写"8080",否则报错listen tcp: address 8080: missing port in address - 如果端口被占用,
ListenAndServe返回非nilerror,但进程不会自动退出——需用log.Fatal或显式处理
处理请求体时,r.Body 必须关闭,且不能重复读取
Go 的 http.Request.Body 是 io.ReadCloser,不关会导致文件描述符泄漏;而它是一次性流,多次调用 io.ReadAll(r.Body) 第二次会读到空字节。
- 总是用
defer r.Body.Close()(注意:放在 handler 函数开头,别等逻辑分支后再 defer) - 需要多次读取时(比如先校验 JSON 结构、再解码),用
io.ReadAll读一次存为[]byte,再用bytes.NewReader构造新 reader - POST 表单数据(
application/x-www-form-urlencoded)应优先用r.ParseForm()+r.FormValue("key"),而非直接读Body
静态文件服务别硬编码路径,用 http.FileServer + http.StripPrefix 组合
想让 /static/xxx.js 映射到本地 ./assets/xxx.js,直接 http.ServeFile 只能处理单个文件;用 http.FileServer 能服务整个目录,但默认会暴露完整磁盘路径——必须剥离前缀。
立即学习“go语言免费学习笔记(深入)”;
fs := http.FileServer(http.Dir("./assets"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
-
http.Dir参数是**本地文件系统路径**,不是 URL 路径;它不支持嵌套 glob 或排除规则 -
StripPrefix的第二个参数必须是http.Handler,传fs没问题,但传nil或函数会 panic - 生产环境禁用此方式提供静态资源——没缓存头、无压缩、不支持 range 请求,应交由 Nginx 或 CDN
HTTP/2 支持依赖 TLS,纯 HTTP 不会自动启用
Go 1.6+ 默认支持 HTTP/2,但仅当服务器启用了 TLS(即使用 ListenAndServeTLS)且客户端也支持时才协商成功。用 ListenAndServe 走明文 HTTP,哪怕客户端发的是 HTTP/2 请求,也会降级为 HTTP/1.1。
- 本地开发可生成自签名证书:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes - 启动时改用
server.ListenAndServeTLS("cert.pem", "key.pem"),浏览器访问https://localhost:8080才可能看到 HTTP/2 - 若证书不合法(如域名不匹配、过期),Chrome 会拒绝连接;curl 加
-k可跳过验证,但 Go 程序默认仍校验
HTTP/2 的 server push、header 压缩等功能都建立在 TLS 层之上,这点和配置无关,是协议强制要求。










