2. Go Web基础回顾

2.1 HTTP 协议核心要素

HTTP(HyperText Transfer Protocol)是 Web 服务的通信基石。Go 的 net/http 标准库完整实现了 HTTP/1.1 和 HTTP/2 协议,理解其核心要素是编写正确 Web 服务的前提。

要素 说明 Go 中对应类型/方法
请求方法 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS http.MethodGet、http.MethodPost 等常量
URL 路径 标识资源的唯一地址,可包含查询参数 *http.Request.URL.Path、URL.Query()
请求头 携带元数据:Content-Type、Authorization、Accept 等 http.Header 类型,r.Header.Get(key)
请求体 POST/PUT 时传输 JSON、表单、文件等数据 r.Body(io.ReadCloser)
状态码 服务端处理结果标识:200、201、400、404、500 等 http.StatusOK、http.StatusNotFound 等常量
响应体 服务端返回的数据,通常为 JSON、HTML 或纯文本 w.Write()、json.NewEncoder(w).Encode()
契约压测视角: 压测时需精确构造请求方法、路径、头、体,并验证响应状态码与体结构。任何偏差都会导致测试失败或误报。

2.2 使用 net/http 快速搭建 Web 服务

Go 标准库 net/http 无需第三方依赖即可启动 HTTP 服务。以下是最小可运行的服务示例:

package main

import (
    "encoding/json"
    "log"
    "net/http"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

func getUserHandler(w http.ResponseWriter, r *http.Request) {
    // 仅允许 GET 方法
    if r.Method != http.MethodGet {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }

    user := User{ID: 1, Name: "Alice"}
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(user)
}

func main() {
    http.HandleFunc("/api/user", getUserHandler)
    log.Println("Server starting on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
关键点:
  • http.HandleFunc 注册路由处理函数,默认使用 DefaultServeMux。
  • http.ListenAndServe 启动 TCP 监听并处理 HTTP 请求。
  • 响应需显式设置 Content-Type 和状态码,否则默认 text/plain; charset=utf-8。

2.3 路由与 ServeMux 机制

Go 标准库的路由器是 http.ServeMux,它基于路径前缀匹配,不支持参数化路由(如 /user/:id)。

路由模式 匹配规则 示例
精确路径 完全匹配请求路径 /api/user 只匹配 /api/user
子树路径 以 / 结尾,匹配该路径下的所有子路径 /api/ 匹配 /api/user、/api/order
根路径 / 匹配所有未匹配的路径(兜底) / 作为 404 处理或静态文件服务
注意: ServeMux 不支持路径参数、HTTP 方法路由(需在 Handler 内手动判断 Method)。生产级服务建议使用 gorilla/mux、chi 或 Go 1.22+ 的增强路由。
net/http 请求处理流程 客户端 ServeMux 路由 Handler 处理 响应返回 流程说明: 1. 客户端发起 HTTP 请求 → 2. ServeMux 根据路径匹配 Handler → 3. Handler 处理业务逻辑 4. 写入响应状态码、Header、Body → 5. 响应返回客户端

2.4 中间件概念与链式处理

中间件(Middleware)是包裹在核心 Handler 前后的处理函数,用于横切关注点:日志、鉴权、限流、超时控制等。Go 中典型的中间件模式是函数式嵌套:

// 中间件类型:接收 Handler,返回 Handler
type Middleware func(http.Handler) http.Handler

// 日志中间件
func LoggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("[%s] %s %s", r.Method, r.URL.Path, r.RemoteAddr)
        next.ServeHTTP(w, r) // 调用下一个 Handler
    })
}

// 鉴权中间件
func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if token == "" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        // 验证 token...
        next.ServeHTTP(w, r)
    })
}

// 链式组合
func main() {
    handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })

    // 从内到外:Auth → Logging → handler
    wrapped := LoggingMiddleware(AuthMiddleware(handler))
    http.Handle("/api/secure", wrapped)
    http.ListenAndServe(":8080", nil)
}
中间件执行顺序:
  • 请求进入时:LoggingMiddleware → AuthMiddleware → 核心 Handler
  • 响应返回时:核心 Handler → AuthMiddleware → LoggingMiddleware
  • 任一中间件调用 http.Error 或 w.WriteHeader 后,后续中间件和 Handler 不再执行。
中间件洋葱模型(请求/响应穿透) 请求入口 日志中间件 鉴权中间件 核心 Handler 响应出口 中间件特性: • 请求按注册顺序正向穿透中间件链,到达核心 Handler • 响应按反向顺序返回,每个中间件可修改响应或记录耗时

2.5 契约压测视角:为什么需要回顾这些基础?

  • 路由匹配: 压测脚本必须使用正确的路径和 HTTP 方法,否则请求无法到达目标 Handler。
  • 中间件影响: 鉴权、限流、日志中间件会改变请求处理路径和响应时间,压测需考虑中间件开销。
  • 响应结构: 契约验证依赖精确的响应状态码、Header 和 Body 结构,这些由 Handler 和中间件共同决定。
  • 错误处理: 中间件或 Handler 中未捕获的 panic 会导致 500 响应,压测需覆盖异常路径。
最佳实践: 在编写压测脚本前,先通过 curl 或 Postman 手动验证每个接口的请求/响应契约,确保基础通信无误。