20 - HTTP:net/http 包、客户端、服务器、中间件
20 - HTTP
20.1 HTTP 客户端
基本请求
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
func main() {
// GET 请求
resp, err := http.Get("https://httpbin.org/get")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("状态码:", resp.StatusCode)
fmt.Println("响应:", string(body))
// POST JSON
data := map[string]string{"name": "Alice", "email": "[email protected]"}
jsonData, _ := json.Marshal(data)
resp2, err := http.Post(
"https://httpbin.org/post",
"application/json",
bytes.NewReader(jsonData),
)
if err != nil {
panic(err)
}
defer resp2.Body.Close()
body2, _ := io.ReadAll(resp2.Body)
fmt.Println(string(body2))
// 带 header 的请求
req, _ := http.NewRequest("GET", "https://httpbin.org/headers", nil)
req.Header.Set("Authorization", "Bearer token123")
req.Header.Set("X-Request-ID", "req-abc")
client := &http.Client{Timeout: 10 * time.Second}
resp3, _ := client.Do(req)
defer resp3.Body.Close()
body3, _ := io.ReadAll(resp3.Body)
fmt.Println(string(body3))
}
自定义 Client
// 创建带超时的客户端
client := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
DisableCompression: false,
},
}
// 带 context 的请求
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", "https://example.com", nil)
resp, err := client.Do(req)
20.2 HTTP 服务器
基本服务器
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
func main() {
// 注册路由
http.HandleFunc("/", homeHandler)
http.HandleFunc("/hello", helloHandler)
http.HandleFunc("/api/users", usersHandler)
// 启动服务器
log.Println("服务器启动在 :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "欢迎来到首页!")
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
name = "World"
}
fmt.Fprintf(w, "Hello, %s!", name)
}
func usersHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
users := []map[string]any{
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
case http.MethodPost:
var user map[string]any
json.NewDecoder(r.Body).Decode(&user)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
ServeMux(Go 1.22+ 增强路由)
func main() {
mux := http.NewServeMux()
// Go 1.22+ 支持方法和路径参数
mux.HandleFunc("GET /api/users", listUsers)
mux.HandleFunc("POST /api/users", createUser)
mux.HandleFunc("GET /api/users/{id}", getUser)
mux.HandleFunc("DELETE /api/users/{id}", deleteUser)
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
}
log.Fatal(server.ListenAndServe())
}
func getUser(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id") // Go 1.22+
fmt.Fprintf(w, "User ID: %s", id)
}
优雅关闭
func main() {
srv := &http.Server{Addr: ":8080"}
// 监听系统信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-quit
log.Println("正在关闭服务器...")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
srv.Shutdown(ctx)
}()
log.Println("服务器启动在 :8080")
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
log.Println("服务器已关闭")
}
20.3 中间件模式
type Middleware func(http.Handler) http.Handler
// 日志中间件
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %s %v", r.RemoteAddr, r.Method, r.URL.Path, time.Since(start))
})
}
// CORS 中间件
func CORSMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
// 认证中间件
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)
})
}
// Recovery 中间件
func RecoveryMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("panic: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}
// 中间件链
func Chain(handler http.Handler, middlewares ...Middleware) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler)
}
return handler
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", homeHandler)
handler := Chain(mux,
RecoveryMiddleware,
LoggingMiddleware,
CORSMiddleware,
)
http.ListenAndServe(":8080", handler)
}
20.4 响应写入工具
// JSON 响应
func respondJSON(w http.ResponseWriter, status int, data any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
// 错误响应
func respondError(w http.ResponseWriter, status int, message string) {
respondJSON(w, status, map[string]string{"error": message})
}
// 读取 JSON 请求体
func readJSON(r *http.Request, dst any) error {
dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields()
return dec.Decode(dst)
}
// 使用示例
func createUserHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
Name string `json:"name"`
Email string `json:"email"`
}
if err := readJSON(r, &req); err != nil {
respondError(w, http.StatusBadRequest, "Invalid request body")
return
}
// 创建用户...
respondJSON(w, http.StatusCreated, map[string]any{
"id": 1,
"name": req.Name,
"email": req.Email,
})
}
🏢 业务场景
- REST API:http.HandleFunc + JSON 序列化构建 API
- 微服务通信:HTTP 客户端调用下游服务
- 反向代理:httputil.ReverseProxy 实现反向代理
- 文件上传:multipart.Reader 处理文件上传
- 健康检查:HTTP handler 实现 /health 端点
📖 扩展阅读