当前位置: 首页 > news >正文

Go语言net/http与Web开发:构建高性能HTTP服务

引言

Go语言的标准库net/http提供了完善的HTTP服务端和客户端实现,其设计简洁优雅,性能优异,是构建Web服务的主流选择。本文将深入剖析HTTP服务端的核心组件请求处理流程、中间件模式以及客户端使用,并通过实际案例展示如何构建完整的HTTP服务。

一、HTTP服务端核心概念

1.1 最简单的HTTP服务器

package main ​ import ( "fmt" "net/http" ) ​ func main() { // HandleFunc注册路由处理器 http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World!") }) ​ // 监听端口并启动服务 fmt.Println("Server starting on :8080") if err := http.ListenAndServe(":8080", nil); err != nil { fmt.Printf("Server error: %v\n", err) } }

1.2 Handler接口解析

http.Handler是HTTP服务的核心接口:

type Handler interface { ServeHTTP(ResponseWriter, *Request) }

任何实现此接口的类型都可以作为处理器:

package main ​ import ( "fmt" "net/http" ) ​ // 自定义处理器类型 type greetingHandler struct { prefix string } ​ // 实现Handler接口 func (g *greetingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "%s from custom handler!", g.prefix) } ​ type statusHandler struct { statusCode int } ​ func (s *statusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.WriteHeader(s.statusCode) fmt.Fprintf(w, "Status code: %d", s.statusCode) } ​ func main() { mux := http.NewServeMux() ​ // 使用自定义处理器 mux.Handle("/hello", &greetingHandler{prefix: "Hello"}) mux.Handle("/status", &statusHandler{statusCode: http.StatusOK}) ​ fmt.Println("Server starting on :8080") http.ListenAndServe(":8080", mux) }

1.3 ServeMux路由多路复用器

ServeMux是Go内置的路由多路复用器,支持基于模式匹配的分发:

package main ​ import ( "fmt" "net/http" ) ​ func main() { mux := http.NewServeMux() ​ // 精确匹配 mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "List all users") }) ​ mux.HandleFunc("/users/", func(w http.ResponseWriter, r *http.Request) { // 通过Request.URL.Path获取路径 fmt.Fprintf(w, "User ID: %s", r.URL.Path[len("/users/"):]) }) ​ // 使用路径参数模式 mux.HandleFunc("/products/", func(w http.ResponseWriter, r *http.Request) { parts := r.URL.Path[len("/products/"):] fmt.Fprintf(w, "Product path: %s", parts) }) ​ fmt.Println("Server starting on :8080") http.ListenAndServe(":8080", mux) }

二、请求处理流程与响应构建

2.1 请求对象详解

http.Request包含客户端请求的所有信息:

package main ​ import ( "encoding/json" "fmt" "net/http" ) ​ func inspectRequest(w http.ResponseWriter, r *http.Request) { info := map[string]interface{}{ "Method": r.Method, "URL": r.URL.String(), "Path": r.URL.Path, "RawQuery": r.URL.RawQuery, "Host": r.Host, "RemoteAddr": r.RemoteAddr, "Protocol": r.Proto, "Header": r.Header, "ContentLength": r.ContentLength, "TransferEncoding": r.TransferEncoding, } ​ w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(info) } ​ func main() { http.HandleFunc("/inspect", inspectRequest) http.ListenAndServe(":8080", nil) }

2.2 请求体读取

package main ​ import ( "encoding/json" "fmt" "io" "net/http" ) ​ type User struct { Name string `json:"name"` Email string `json:"email"` } ​ func readJSONBody(w http.ResponseWriter, r *http.Request) { // 确保内容类型是JSON if r.Header.Get("Content-Type") != "application/json" { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "Expected Content-Type: application/json") return } ​ // 限制请求体大小,防止过大请求 r.Body = http.MaxBytesReader(w, r.Body, 1024*1024) // 1MB限制 ​ defer r.Body.Close() ​ var user User decoder := json.NewDecoder(r.Body) // 支持解析未知字段 decoder.DisallowUnknownFields() ​ if err := decoder.Decode(&user); err != nil { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "Invalid JSON: %v", err) return } ​ fmt.Printf("Received user: %+v\n", user) fmt.Fprintf(w, "User %s (%s) received", user.Name, user.Email) } ​ func main() { http.HandleFunc("/user", readJSONBody) http.ListenAndServe(":8080", nil) }

2.3 响应构建

package main ​ import ( "encoding/json" "fmt" "net/http" "time" ) ​ type Response struct { Success bool `json:"success"` Message string `json:"message,omitempty"` Data interface{} `json:"data,omitempty"` Error string `json:"error,omitempty"` } ​ func writeJSON(w http.ResponseWriter, statusCode int, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) json.NewEncoder(w).Encode(data) } ​ func successResponse(w http.ResponseWriter, data interface{}) { writeJSON(w, http.StatusOK, Response{ Success: true, Data: data, }) } ​ func errorResponse(w http.ResponseWriter, statusCode int, message string) { writeJSON(w, statusCode, Response{ Success: false, Error: message, }) } ​ func jsonAPI(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: successResponse(w, map[string]interface{}{ "time": time.Now().Unix(), "message": "GET request successful", }) case http.MethodPost: var data map[string]interface{} if err := json.NewDecoder(r.Body).Decode(&data); err != nil { errorResponse(w, http.StatusBadRequest, "Invalid JSON") return } successResponse(w, map[string]interface{}{ "received": data, }) default: errorResponse(w, http.StatusMethodNotAllowed, "Method not allowed") } } ​ func main() { http.HandleFunc("/api", jsonAPI) http.ListenAndServe(":8080", nil) }

2.4 ResponseWriter原理

http.ResponseWriter是一个接口:

type ResponseWriter interface { Header() Header Write([]byte) (int, error) WriteHeader(statusCode int) }

写入顺序很重要:

package main ​ import ( "fmt" "net/http" ) ​ func badExample(w http.ResponseWriter, r *http.Request) { // 错误:先Write后WriteHeader w.Write([]byte("Content")) // 隐式调用WriteHeader(200) w.WriteHeader(http.StatusInternalServerError) // 已经发送了200,这里无效 } ​ func goodExample(w http.ResponseWriter, r *http.Request) { // 正确:先WriteHeader后Write w.WriteHeader(http.StatusOK) w.Write([]byte("Content")) } ​ func main() { http.HandleFunc("/bad", badExample) http.HandleFunc("/good", goodExample) http.ListenAndServe(":8080", nil) }

三、中间件模式实现

3.1 中间件基础

中间件是一个返回http.Handler的函数:

package main ​ import ( "fmt" "log" "net/http" "time" ) ​ // 中间件函数签名 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() ​ // 使用responsewriter的包装器来记录状态码 wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK} ​ next.ServeHTTP(wrapped, r) ​ log.Printf("%s %s %d %v", r.Method, r.URL.Path, wrapped.statusCode, time.Since(start)) }) } ​ type responseWriter struct { http.ResponseWriter statusCode int } ​ func (rw *responseWriter) WriteHeader(code int) { rw.statusCode = code rw.ResponseWriter.WriteHeader(code) } ​ func (rw *responseWriter) Write(b []byte) (int, error) { if rw.statusCode == 0 { rw.statusCode = http.StatusOK } return rw.ResponseWriter.Write(b) } ​ // 认证中间件 func AuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") if token == "" { w.WriteHeader(http.StatusUnauthorized) fmt.Fprintf(w, "Missing authorization token") return } ​ // 验证token(简化示例) if !validateToken(token) { w.WriteHeader(http.StatusUnauthorized) fmt.Fprintf(w, "Invalid token") return } ​ next.ServeHTTP(wrapped, r) }) } ​ func validateToken(token string) bool { // 实际应该验证JWT或其他token机制 return token == "valid-token-123" } ​ func main() { finalHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Protected resource!") }) ​ // 组合中间件 handler := LoggingMiddleware(finalHandler) // handler = AuthMiddleware(handler) ​ http.Handle("/protected", handler) http.HandleFunc("/public", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Public resource!") }) ​ http.ListenAndServe(":8080", nil) }

3.2 中间件链式组合

package main ​ import ( "fmt" "log" "net/http" "time" ) ​ type Middleware func(http.Handler) http.Handler ​ // 链式组合多个中间件 func Chain(h http.Handler, middlewares ...Middleware) http.Handler { for i := len(middlewares) - 1; i >= 0; i-- { h = middlewares[i](h) } return h } ​ // 各个中间件实现 func WithTimeout(timeout time.Duration) Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { done := make(chan struct{}) go func() { next.ServeHTTP(w, r) close(done) }() ​ select { case <-done: return case <-time.After(timeout): log.Printf("Request timeout: %s %s", r.Method, r.URL.Path) w.WriteHeader(http.StatusGatewayTimeout) fmt.Fprintf(w, "Request timeout") } }) } } ​ func WithCORS(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 WithRecovery(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 recovered: %v", err) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Internal server error") } }() next.ServeHTTP(w, r) }) } ​ func mainHandler(w http.ResponseWriter, r *http.Request) { // 模拟业务逻辑 time.Sleep(100 * time.Millisecond) fmt.Fprintf(w, "Hello, World!") } ​ func main() { handler := Chain( http.HandlerFunc(mainHandler), WithRecovery, WithCORS, WithTimeout(5*time.Second), ) ​ http.Handle("/", handler) log.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) }

3.3 第三方中间件框架

实际项目中可以使用negroni等成熟框架:

package main ​ import ( "fmt" "log" "net/http" ​ "github.com/urfave/negroni" ) ​ func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello from main handler!") }) ​ n := negroni.New() ​ // 使用中间件 n.Use(negroni.NewLogger()) n.Use(negroni.NewRecovery()) n.Use(negroni.NewCORS()) ​ // 添加自定义中间件 n.UseFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { log.Printf("Before request: %s", r.URL.Path) next(rw, r) log.Printf("After request: %s", r.URL.Path) }) ​ n.UseHandler(mux) ​ log.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", n)) }

四、HTTP客户端使用

4.1 基本客户端请求

package main ​ import ( "fmt" "io" "net/http" "time" ) ​ func main() { // 创建客户端并设置超时 client := &http.Client{ Timeout: 10 * time.Second, } ​ // GET请求 resp, err := client.Get("https://api.example.com/data") if err != nil { fmt.Printf("GET request failed: %v\n", err) return } defer resp.Body.Close() ​ body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Read body failed: %v\n", err) return } ​ fmt.Printf("Status: %d\n", resp.StatusCode) fmt.Printf("Body: %s\n", string(body)) }

4.2 设置请求头和自定义请求

package main ​ import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) ​ func main() { client := &http.Client{} ​ // 创建自定义请求 reqBody := map[string]interface{}{ "username": "testuser", "password": "securepass", } jsonBody, _ := json.Marshal(reqBody) ​ req, err := http.NewRequest("POST", "https://api.example.com/login", bytes.NewBuffer(jsonBody)) if err != nil { fmt.Printf("Create request failed: %v\n", err) return } ​ // 设置请求头 req.Header.Set("Content-Type", "application/json") req.Header.Set("User-Agent", "MyGoClient/1.0") req.Header.Set("Accept", "application/json") ​ // 发送请求 resp, err := client.Do(req) if err != nil { fmt.Printf("Request failed: %v\n", err) return } defer resp.Body.Close() ​ body, _ := io.ReadAll(resp.Body) fmt.Printf("Response: %s\n", string(body)) }

4.3 处理Cookies

package main ​ import ( "fmt" "net/http" ) ​ func main() { client := &http.Client{} ​ // 第一次请求,获取Cookie req1, _ := http.NewRequest("GET", "https://example.com/login", nil) resp1, err := client.Do(req1) if err != nil { fmt.Printf("Request 1 failed: %v\n", err) return } ​ cookies := resp1.Cookies() fmt.Printf("Got %d cookies\n", len(cookies)) resp1.Body.Close() ​ // 第二次请求,带上Cookie req2, _ := http.NewRequest("GET", "https://example.com/profile", nil) for _, cookie := range cookies { req2.AddCookie(cookie) fmt.Printf("Cookie: %s=%s\n", cookie.Name, cookie.Value) } ​ resp2, err := client.Do(req2) if err != nil { fmt.Printf("Request 2 failed: %v\n", err) return } defer resp2.Body.Close() ​ fmt.Printf("Profile response status: %d\n", resp2.StatusCode) }

五、TCP保活与超时控制

5.1 连接池与复用

package main ​ import ( "fmt" "io" "net/http" "sync" "time" ) ​ // 使用共享的HTTP客户端(包含连接池) var httpClient = &http.Client{ Transport: &http.Transport{ MaxIdleConns: 100, // 最大空闲连接数 MaxIdleConnsPerHost: 10, // 每个主机最大空闲连接 IdleConnTimeout: 90 * time.Second, // 空闲连接超时 }, Timeout: 30 * time.Second, } ​ func fetchURLs(urls []string) []string { var wg sync.WaitGroup results := make([]string, len(urls)) var mu sync.Mutex ​ for i, url := range urls { wg.Add(1) go func(idx int, u string) { defer wg.Done() ​ resp, err := httpClient.Get(u) if err != nil { results[idx] = fmt.Sprintf("Error: %v", err) return } defer resp.Body.Close() ​ body, _ := io.ReadAll(resp.Body) mu.Lock() results[idx] = fmt.Sprintf("%s: %d bytes", u, len(body)) mu.Unlock() }(i, url) } ​ wg.Wait() return results } ​ func main() { urls := []string{ "https://example.com", "https://example.org", "https://example.net", } ​ results := fetchURLs(urls) for _, r := range results { fmt.Println(r) } }

5.2 超时控制详解

package main ​ import ( "context" "fmt" "net/http" "time" ) ​ func main() { // 1. 整体客户端超时 client := &http.Client{ Timeout: 5 * time.Second, } ​ // 2. 使用Context控制超时 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() ​ req, _ := http.NewRequestWithContext(ctx, "GET", "https://httpbin.org/delay/10", nil) ​ resp, err := client.Do(req) if err != nil { if ctx.Err() == context.DeadlineExceeded { fmt.Println("Request timed out!") } else { fmt.Printf("Request failed: %v\n", err) } return } defer resp.Body.Close() ​ fmt.Printf("Response status: %d\n", resp.StatusCode) } ​ // 分层超时示例 func layeredTimeoutExample() { // 创建带有超时的Context ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() ​ // 创建请求 req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.example.com/data", nil) ​ // 使用http.Transport设置各层超时 transport := &http.Transport{ DialContext: (&net.Dialer{ Timeout: 1 * time.Second, // 连接建立超时 KeepAlive: 30 * time.Second, }).DialContext, ResponseHeaderTimeout: 1 * time.Second, // 读取响应头超时 ExpectContinueTimeout: 1 * time.Second, } ​ client := &http.Client{ Transport: transport, } ​ resp, err := client.Do(req) if err != nil { fmt.Printf("Request failed: %v\n", err) return } defer resp.Body.Close() ​ fmt.Printf("Response status: %d\n", resp.StatusCode) }

六、RESTful API设计原则

6.1 RESTful路由设计

package main ​ import ( "encoding/json" "fmt" "net/http" "strconv" "strings" ) ​ // RESTful资源处理器 type UserHandler struct{} ​ func (h *UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.Path parts := strings.Split(strings.Trim(path, "/"), "/") ​ // /users - 资源集合 // /users/:id - 单个资源 if len(parts) == 1 && parts[0] == "users" { switch r.Method { case http.MethodGet: h.ListUsers(w, r) case http.MethodPost: h.CreateUser(w, r) } return } ​ if len(parts) == 2 && parts[0] == "users" { id, err := strconv.Atoi(parts[1]) if err != nil { http.Error(w, "Invalid user ID", http.StatusBadRequest) return } ​ switch r.Method { case http.MethodGet: h.GetUser(w, r, id) case http.MethodPut: h.UpdateUser(w, r, id) case http.MethodDelete: h.DeleteUser(w, r, id) } return } ​ http.NotFound(w, r) } ​ func (h *UserHandler) ListUsers(w http.ResponseWriter, r *http.Request) { users := []map[string]interface{}{ {"id": 1, "name": "张三"}, {"id": 2, "name": "李四"}, } writeJSON(w, http.StatusOK, users) } ​ func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) { var user map[string]interface{} if err := json.NewDecoder(r.Body).Decode(&user); err != nil { http.Error(w, "Invalid JSON", http.StatusBadRequest) return } user["id"] = 3 // 模拟创建 writeJSON(w, http.StatusCreated, user) } ​ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request, id int) { user := map[string]interface{}{ "id": id, "name": fmt.Sprintf("User %d", id), } writeJSON(w, http.StatusOK, user) } ​ func (h *UserHandler) UpdateUser(w http.ResponseWriter, r *http.Request, id int) { var updates map[string]interface{} if err := json.NewDecoder(r.Body).Decode(&updates); err != nil { http.Error(w, "Invalid JSON", http.StatusBadRequest) return } updates["id"] = id writeJSON(w, http.StatusOK, updates) } ​ func (h *UserHandler) DeleteUser(w http.ResponseWriter, r *http.Request, id int) { writeJSON(w, http.StatusOK, map[string]interface{}{ "message": fmt.Sprintf("User %d deleted", id), }) } ​ func writeJSON(w http.ResponseWriter, status int, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(data) } ​ func main() { handler := &UserHandler{} http.Handle("/users/", handler) ​ fmt.Println("RESTful API server starting on :8080") http.ListenAndServe(":8080", nil) }

6.2 错误处理规范

package main ​ import ( "encoding/json" "fmt" "net/http" ) ​ // RFC 7807 Problem Details for HTTP APIs type ProblemDetail struct { Type string `json:"type"` Title string `json:"title"` Status int `json:"status"` Detail string `json:"detail"` Instance string `json:"instance"` } ​ func writeProblem(w http.ResponseWriter, status int, title, detail string) { problem := ProblemDetail{ Type: fmt.Sprintf("https://example.com/probs/%d", status), Title: title, Status: status, Detail: detail, Instance: "/users", // 简化 } ​ w.Header().Set("Content-Type", "application/problem+json") w.WriteHeader(status) json.NewEncoder(w).Encode(problem) } ​ func userHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeProblem(w, http.StatusMethodNotAllowed, "Method Not Allowed", "Only GET method is supported for this endpoint") return } ​ userID := r.URL.Query().Get("id") if userID == "" { writeProblem(w, http.StatusBadRequest, "Missing Required Parameter", "The 'id' query parameter is required") return } ​ fmt.Fprintf(w, "User: %s", userID) } ​ func main() { http.HandleFunc("/users", userHandler) http.ListenAndServe(":8080", nil) }

七、实际案例:构建完整的HTTP服务

7.1 项目结构

myapp/ ├── main.go ├── handlers/ │ ├── user.go │ └── product.go ├── middleware/ │ ├── logging.go │ └── auth.go ├── models/ │ └── models.go └── go.mod

7.2 完整实现

package main ​ import ( "context" "encoding/json" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" ) ​ // ============ 模型定义 ============ ​ type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` } ​ type Product struct { ID int `json:"id"` Name string `json:"name"` Price float64 `json:"price"` Quantity int `json:"quantity"` } ​ type Order struct { ID int `json:"id"` UserID int `json:"user_id"` Products []Product `json:"products"` Total float64 `json:"total"` CreatedAt time.Time `json:"created_at"` } ​ type APIResponse struct { Success bool `json:"success"` Data interface{} `json:"data,omitempty"` Error string `json:"error,omitempty"` Meta *Meta `json:"meta,omitempty"` } ​ type Meta struct { Page int `json:"page,omitempty"` PageSize int `json:"page_size,omitempty"` TotalCount int `json:"total_count,omitempty"` } ​ // ============ 中间件 ============ ​ type loggingResponseWriter struct { http.ResponseWriter statusCode int size int } ​ func (w *loggingResponseWriter) WriteHeader(code int) { w.statusCode = code w.ResponseWriter.WriteHeader(code) } ​ func (w *loggingResponseWriter) Write(b []byte) (int, error) { size, err := w.ResponseWriter.Write(b) w.size += size return size, err } ​ func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() lrw := &loggingResponseWriter{w, http.StatusOK, 0} ​ next.ServeHTTP(lrw, r) ​ log.Printf("[%s] %s %s %d %d bytes %v", r.Method, r.URL.Path, r.RemoteAddr, lrw.statusCode, lrw.size, time.Since(start)) }) } ​ 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 recovered: %v", err) writeJSON(w, http.StatusInternalServerError, APIResponse{ Success: false, Error: "Internal server error", }) } }() next.ServeHTTP(w, r) }) } ​ 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) }) } ​ // ============ 处理器 ============ ​ type UserHandler struct { users []User } ​ func NewUserHandler() *UserHandler { return &UserHandler{ users: []User{ {ID: 1, Name: "张三", Email: "zhangsan@example.com"}, {ID: 2, Name: "李四", Email: "lisi@example.com"}, }, } } ​ func (h *UserHandler) ListUsers(w http.ResponseWriter, r *http.Request) { page, _ := strconv.Atoi(r.URL.Query().Get("page")) pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size")) ​ if page <= 0 { page = 1 } if pageSize <= 0 || pageSize > 100 { pageSize = 10 } ​ start := (page - 1) * pageSize end := start + pageSize ​ if start >= len(h.users) { writeJSON(w, http.StatusOK, APIResponse{ Success: true, Data: []User{}, Meta: &Meta{Page: page, PageSize: pageSize, TotalCount: len(h.users)}, }) return } ​ if end > len(h.users) { end = len(h.users) } ​ writeJSON(w, http.StatusOK, APIResponse{ Success: true, Data: h.users[start:end], Meta: &Meta{Page: page, PageSize: pageSize, TotalCount: len(h.users)}, }) } ​ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request, id int) { for _, user := range h.users { if user.ID == id { writeJSON(w, http.StatusOK, APIResponse{Success: true, Data: user}) return } } writeJSON(w, http.StatusNotFound, APIResponse{ Success: false, Error: "User not found", }) } ​ type ProductHandler struct { products []Product } ​ func NewProductHandler() *ProductHandler { return &ProductHandler{ products: []Product{ {ID: 1, Name: "iPhone 15", Price: 7999.00, Quantity: 100}, {ID: 2, Name: "MacBook Pro", Price: 19999.00, Quantity: 50}, }, } } ​ func (h *ProductHandler) ListProducts(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, APIResponse{Success: true, Data: h.products}) } ​ func (h *ProductHandler) GetProduct(w http.ResponseWriter, r *http.Request, id int) { for _, p := range h.products { if p.ID == id { writeJSON(w, http.StatusOK, APIResponse{Success: true, Data: p}) return } } writeJSON(w, http.StatusNotFound, APIResponse{Success: false, Error: "Product not found"}) } ​ // ============ 辅助函数 ============ ​ func writeJSON(w http.ResponseWriter, status int, resp APIResponse) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(resp) } ​ func requireJSON(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Content-Type") != "application/json" { writeJSON(w, http.StatusUnsupportedMediaType, APIResponse{ Success: false, Error: "Content-Type must be application/json", }) return } next(w, r) } } ​ // ============ 路由设置 ============ ​ func setupRoutes(userHandler *UserHandler, productHandler *ProductHandler) *http.ServeMux { mux := http.NewServeMux() ​ // 用户路由 mux.HandleFunc("GET /api/users", userHandler.ListUsers) mux.HandleFunc("GET /api/users/", func(w http.ResponseWriter, r *http.Request) { idStr := r.URL.Path[len("/api/users/"):] id, err := strconv.Atoi(idStr) if err != nil { writeJSON(w, http.StatusBadRequest, APIResponse{Success: false, Error: "Invalid user ID"}) return } userHandler.GetUser(w, r, id) }) ​ // 产品路由 mux.HandleFunc("GET /api/products", productHandler.ListProducts) mux.HandleFunc("GET /api/products/", func(w http.ResponseWriter, r *http.Request) { idStr := r.URL.Path[len("/api/products/"):] id, err := strconv.Atoi(idStr) if err != nil { writeJSON(w, http.StatusBadRequest, APIResponse{Success: false, Error: "Invalid product ID"}) return } productHandler.GetProduct(w, r, id) }) ​ // 健康检查 mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, APIResponse{Success: true, Data: map[string]string{"status": "healthy"}}) }) ​ return mux } ​ // ============ 主函数 ============ ​ import ( "strconv" ) ​ func main() { userHandler := NewUserHandler() productHandler := NewProductHandler() mux := setupRoutes(userHandler, productHandler) ​ // 创建服务器 server := &http.Server{ Addr: ":8080", Handler: chainHandlers(mux, recoveryMiddleware, loggingMiddleware, corsMiddleware), ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, IdleTimeout: 60 * time.Second, } ​ // 启动服务器到Goroutine go func() { log.Println("Server starting on :8080") if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("Server failed: %v", err) } }() ​ // 优雅关闭 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit ​ log.Println("Shutting down server...") ​ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() ​ if err := server.Shutdown(ctx); err != nil { log.Fatalf("Server forced to shutdown: %v", err) } ​ log.Println("Server exited properly") } ​ func chainHandlers(h http.Handler, middlewares ...func(http.Handler) http.Handler) http.Handler { for i := len(middlewares) - 1; i >= 0; i-- { h = middlewares[i](h) } return h }

总结

本文全面介绍了Go语言net/http包的Web开发能力:

  1. Handler与ServeMux:理解http.Handler接口和ServeMux路由多路复用器是构建HTTP服务的基础。

  2. 请求处理流程:深入理解http.Requesthttp.ResponseWriter的工作原理,正确处理请求和构建响应。

  3. 中间件模式:掌握中间件函数签名和链式组合方式,实现日志、认证、限流等功能。

  4. HTTP客户端:使用http.Client进行HTTP请求,注意连接池和超时控制。

  5. 性能优化:合理设置TCP保活、超时控制、连接池参数以提升服务性能。

  6. RESTful设计:遵循REST原则设计清晰的API接口。

  7. 工程实践:完整的HTTP服务需要考虑中间件链、优雅关闭、健康检查等生产级特性。

Go的net/http包设计简洁但功能完善,足以应对大多数Web开发场景。深入理解其底层原理,才能构建高性能、稳定的Web服务。

http://www.jsqmd.com/news/731686/

相关文章:

  • 3分钟解锁XGP存档自由:这款神器让你告别游戏进度丢失烦恼
  • Cursor Pro破解工具终极指南:5步实现AI编程助手永久免费使用
  • KMS智能激活:如何一键永久激活Windows和Office
  • PCL2启动器下载资源总失败?别急,5步智能修复法帮你彻底搞定
  • 如何高效下载B站大会员4K视频:完整指南与实战技巧
  • 如何快速免费解锁Cursor Pro全部功能:cursor-free-vip完全解决方案
  • MOOTDX终极指南:5分钟快速掌握Python通达信数据获取技巧
  • 专业视频格式转换工具的技术实现与应用
  • 告别IO口不够用!手把手教你用STM32F072驱动PCA9555扩展板(附完整HAL库代码)
  • 如何快速掌握Translumo:免费终极屏幕实时翻译器完整使用指南
  • 群晖百度网盘套件技术方案:实现NAS与云端存储的无缝集成
  • Unity 2024实战:除了做游戏,用DOTS和URP还能搞哪些‘骚操作’?
  • 如何通过Apollo Save Tool轻松管理PS4游戏存档:5个实用场景解决方案
  • 如何用easy-topo在5分钟内画出专业网络拓扑图?
  • 从靶场到实战:用BurpSuite和PHPStudy复现upload-labs 19关的完整心路历程
  • 使用 Taotoken 后 API 调用延迟与稳定性带来的直观体验变化
  • B站m4s视频转换终极教程:3步实现永久保存的完整方案
  • 如何修复华硕电脑WIFI消失,连接不了网络问题
  • 3步掌握抖音视频下载:开源工具助你高效批量下载无水印内容
  • 【全网首发】2026年华东杯数学建模ABC题全量深度解析与冲奖攻略——2026华东杯数学建模(附全代码/论文/数据集)-详细解题思路和论文+完整项目代码+结果图表+全套资源(多套持续更新)
  • 构建智能音乐中心:Xiaomusic如何让小爱音箱突破传统限制
  • 黄山AI获客多引擎自适应算法的GEO优化实现原理拆解
  • 保姆级教程:给Windows上的AnyTXT Searcher穿个‘公网马甲’,打造私人远程文件搜索引擎
  • 制糖设备巡检运维工单管理系统方案
  • CVE-2026-34070 LangChain-Core路径遍历漏洞,任意文件读取附PoC
  • 擦擦视频行业价值与发展趋势
  • Onyx开源应用框架:一体化全栈开发实践与核心设计解析
  • 【新人必备手册】OpenClaw Windows 11 一键安装实操教程(含安装包)
  • 对比官方价格Taotoken提供的折扣与活动价如何节省成本
  • 终极免费方案:用WeReader浏览器扩展打造你的微信读书笔记系统