最小可行web服务需两行核心代码:注册路由和启动监听;http.listenandserve才真正启动服务,端口格式须为":8080",错误须显式处理,get参数用r.url.query().get(),post需先调用r.parseform()。

http.ListenAndServe 必须显式调用
很多人写了 http.HandleFunc 就以为服务起来了,其实它只注册路由,不启动任何监听。http.ListenAndServe 才是真正“把服务跑起来”的那一步。
- 端口格式必须带冒号,
":8080"正确,"8080"会 panic - 第二个参数传
nil表示用默认的http.DefaultServeMux,适合起步,但不推荐用于稍复杂的项目 - 该函数会阻塞当前 goroutine,所以
fmt.Println("done")这类语句写在它后面永远不会执行 - 错误没处理时,端口被占用只会静默失败,建议加
if err != nil { log.Fatal(err) }
GET 和 POST 参数读取方式不同
Go 不自动解析请求体,r.FormValue("key") 看似方便,但背后有隐含前提:必须先调用 r.ParseForm()(或 r.ParseMultipartForm()),否则永远返回空字符串,且无任何报错提示。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- URL 查询参数(如
?id=123)可直接用r.URL.Query().Get("id"),无需预解析 - POST 表单(
application/x-www-form-urlencoded)必须调用r.ParseForm()才能用r.FormValue("name") - 文件上传需用
r.MultipartForm,且ParseMultipartForm必须指定内存阈值,例如r.ParseMultipartForm(32 (32MB) - 漏掉
ParseForm是最常见、最难排查的“参数为空”原因
别用 http.DefaultServeMux 做正式路由
全局的 http.DefaultServeMux 是单例,所有 http.HandleFunc 都往里注册——看似简单,实则污染全局状态,测试难、扩展难、路径冲突难调试。
- 重复注册同一路径会 panic,错误信息是
http: multiple registrations for /health - 前缀匹配规则容易误判:
/api不会匹配/api/users,但/api/(结尾带斜杠)会 - 不支持路径参数(如
/user/:id),只能靠字符串截取或正则,维护成本高 - 建议改用显式
http.NewServeMux(),后续也更容易替换为 Gin/Echo 等框架
超时和关闭必须手动控制
http.ListenAndServe 没有超时、无法优雅关闭。线上部署时,进程被 kill -15 后还在处理旧请求,或慢请求拖垮整个服务,都是典型后果。
- 要用
http.Server结构体:设置ReadTimeout(建连+读 header)、WriteTimeout(响应写出总耗时)、IdleTimeout(keep-alive 空闲时间) - Handler 内部业务逻辑超时,必须用
context.WithTimeout(r.Context(), ...),并确保下游调用(如 DB、HTTP client)都接收并响应这个 context - 进程退出时,要调用
srv.Shutdown()等待活跃请求完成,不能直接os.Exit - 忽略这些,上线后大概率遇到连接泄漏、502、goroutine 泄露
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










