最简 HTTP 服务仅需三行代码:注册根路由、写响应、启动监听;处理 POST 须显式调用 r.ParseForm() 或 r.ParseMultipartForm() 才能获取表单值。

用 net/http 启动最简服务,别碰框架先
Go 自带的 net/http 足够跑通 90% 的轻量 HTTP 场景,没必要一上来就引入 Gin 或 Echo。一个能响应 GET / 的服务,三行代码就能跑起来:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, World!")
})
http.ListenAndServe(":8080", nil)
}
注意两点:http.ListenAndServe 默认不启用 HTTPS,端口要显式指定(":8080");nil 表示使用默认的 http.DefaultServeMux,别传空结构体或自定义 mux 却忘了注册路由。
处理 POST 请求时,必须手动调用 r.ParseForm()
Go 不会自动解析表单或 JSON body,这是新手最常卡住的地方。直接读 r.FormValue("key") 会返回空字符串,除非你先调用:
r.ParseForm() // 解析 application/x-www-form-urlencoded // 或 r.ParseMultipartForm(32 << 20) // 解析 multipart/form-data(如文件上传) // 或 json.NewDecoder(r.Body).Decode(&v) // 解析 JSON,需自己关 r.Body
常见错误包括:ParseForm 被调用多次(会 panic)、在 ParseMultipartForm 前没设 MaxMemory 导致临时文件写满磁盘、JSON 解码后没关闭 r.Body 引发连接复用异常。
立即学习“go语言免费学习笔记(深入)”;
静态文件服务别用 http.FileServer 直接暴露根目录
http.FileServer(http.Dir("./static")) 看似方便,但若路径含 ../,可能越权读取项目外文件。正确做法是用 http.StripPrefix 限定前缀,并确保目录路径是绝对路径:
fs := http.FileServer(http.Dir("/abs/path/to/static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
另外,FileServer 不支持缓存头、Gzip 压缩或 ETag,生产环境建议加一层反向代理(如 Nginx)或用 golang.org/x/net/http2 配合 http.Serve 手动控制响应头。
启动时监听失败常因端口被占或权限不足
运行 http.ListenAndServe(":80", ...) 报 listen tcp :80: bind: permission denied 是 Linux/macOS 常见问题 —— 非 root 用户不能绑定 1–1023 端口。解决方案只有两个:sudo 启动(不推荐),或改用高位端口(如 :8080)再由反代转发;另一类错误是 address already in use,说明端口已被占用,可用 lsof -i :8080(macOS/Linux)或 netstat -ano | findstr :8080(Windows)查进程并 kill。
调试时容易忽略的是:服务启动后没有日志输出,导致你以为它挂了,其实只是阻塞在 ListenAndServe —— 加一行 log.Println("server started on :8080") 再启动,能立刻确认是否真卡在监听阶段。










