用 net/http 启动最简服务只需三行代码:导入 net/http 包,调用 http.ListenAndServe(":8080", nil) 即可监听端口,但未注册路由时所有请求均返回 404。
net/http 启动最简服务Go 自带的 net/http 包不需要额外依赖,三行就能跑起来。核心是调用 http.ListenAndServe,它会阻塞运行,监听指定地址并处理请求。
package main
import "net/http"
func main() {
http.ListenAndServe(":8080", nil)
}
这段代码启动一个监听 :8080 的服务器,但目前没有注册任何路由,所有请求都会返回 404 page not found。它只是“能跑”,不是“能用”。
http.HandleFunc 处理路径要让服务器响应具体 URL,得用 http.HandleFunc 注册处理器函数。它接收两个参数:路径前缀(如 "/")和一个符合 func(http.ResponseWriter, *http.Request) 签名的函数。
"/api" 会匹配 /api、/api/users,但不会匹配 /apix
"" 等价于 "/",表示根路径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.ServeMux 显式管理路由直接用 nil 作为 http.ListenAndServe 的第二个参数,底层会使用默认的 http.DefaultServeMux。但显式创建 http.ServeMux 更可控,也方便测试或替换。
DefaultServeMux(尤其在库中注册 handler 时)*http.ServeMux 给 httptest.NewServer
package main
import (
"fmt"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "ok")
})
mux.HandleFunc("/", func(w htt
p.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Home page")
})
http.ListenAndServe(":8080", mux)
}
运行时报错 listen tcp :8080: bind: address already in use 或 permission denied 是高频问题。
address already in use:检查是否已有进程在监听该端口,可用 lsof -i :8080(macOS/Linux)或 netstat -ano | findstr :8080(Windows)定位并 killpermission denied:尝试绑定 :80 或 :443 等特权端口时,Linux/macOS 需要 root 权限;开发阶段建议改用 :8080、:3000 等非特权端口return 导致后续逻辑执行:在 handler 中写完响应后不 return,可能意外继续执行下一行(比如又写一次 body),引发 http: multiple response.WriteHeader calls
真正上线时,别只靠 ListenAndServe —— 它不支持超时控制、优雅关闭、TLS 自动配置等,这些得靠封装 http.Server 实例来实现。