很多人上来就用 Gin 或者 Echo,但其实标准库的 net/http 已经够用了。理解底层之后再用框架,出了问题才知道往哪查。

最简单的服务

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "hello")
    })
    http.ListenAndServe(":8080", nil)
}

跑起来之后 curl localhost:8080 就能看到响应。

Router 和中间件

http.ServeMux 是标准库内置的路由,Go 1.22 之后支持方法和路径参数了:

mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", getUser)
mux.HandleFunc("POST /users", createUser)

中间件就是一个包裹 http.Handler 的函数,没什么神秘的:

func logger(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("%s %s", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

优雅退出

生产环境必须处理 SIGTERM,否则重启时正在处理的请求会被直接切断:

srv := &http.Server{Addr: ":8080", Handler: mux}

go srv.ListenAndServe()

quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
<-quit

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
srv.Shutdown(ctx)
← 返回