Go 语言 net/http 包详解:从入门到实战

Go 语言的标准库 net/http 提供了强大的 HTTP 客户端和服务端实现,是构建 Web 应用和 API 的基础。本文将从零开始,带你全面掌握 net/http 包的使用,包括服务端搭建、请求处理、路由匹配、参数获取、最佳实践等内容,并重点介绍 Go 1.22 带来的路由增强特性。


一、HTTP 服务端基础

1.1 最简单的 HTTP 服务器

go

复制代码
package main

import (
    "fmt"
    "net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}

func main() {
    http.HandleFunc("/", helloHandler)
    http.ListenAndServe(":8080", nil)
}

1.2 核心接口:http.Handler

任何实现了 ServeHTTP(ResponseWriter, *Request) 方法的类型都可以作为 HTTP 处理器。

go

复制代码
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

1.3 服务启动的两种方式

✅ 使用默认路由(包级别函数)

go

复制代码
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
✅ 自定义 Server 实例(推荐生产环境)

go

复制代码
s := &http.Server{
    Addr:           ":8080",
    Handler:        myHandler,
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())

1.4 支持 HTTPS

go

复制代码
http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)

二、请求与响应处理

2.1 核心对象

  • http.ResponseWriter:构造响应
  • *http.Request:获取请求信息

2.2 构建响应示例

go

复制代码
func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    w.Write([]byte(`{"status": "success"}`))
}

2.3 读取请求信息

go

复制代码
method := r.Method
path := r.URL.Path
userAgent := r.Header.Get("User-Agent")
ip := r.RemoteAddr

三、路由与路径匹配

3.1 基础路由注册

go

复制代码
http.HandleFunc("/", homeHandler)
http.HandleFunc("/users", usersHandler)

3.2 自定义 ServeMux

go

复制代码
mux := http.NewServeMux()
mux.HandleFunc("/", homeHandler)
http.ListenAndServe(":8080", mux)

3.3 Go 1.22+ 路由增强

✅ 方法匹配

go

复制代码
http.HandleFunc("GET /posts/{id}", handleGetPost)
http.HandleFunc("POST /posts", handleCreatePost)
✅ 路径通配符

go

复制代码
http.HandleFunc("GET /posts/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")
    fmt.Fprintf(w, "Post ID: %s", id)
})
✅ 剩余路径匹配

go

复制代码
http.HandleFunc("GET /files/{path...}", func(w http.ResponseWriter, r *http.Request) {
    path := r.PathValue("path")
    fmt.Fprintf(w, "File path: %s", path)
})

3.4 路由优先级规则

  • 最具体模式获胜(Go 1.22+)
  • 传统规则:长路径优先

四、请求方法处理

4.1 方法判断

go

复制代码
switch r.Method {
case http.MethodGet:
    handleGet(w, r)
case http.MethodPost:
    handlePost(w, r)
}

4.2 Go 1.22+ 方法限定

go

复制代码
mux.HandleFunc("GET /users", listUsers)
mux.HandleFunc("POST /users", createUser)

4.3 第三方路由库(gorilla/mux)

go

复制代码
r := mux.NewRouter()
r.HandleFunc("/products/{id:[0-9]+}", productHandler)

五、请求参数处理

参数类型 获取方式 示例
查询参数 r.URL.Query().Get("key") /users?page=1
表单参数 r.FormValue("key") username=john
路径参数 r.PathValue("id") /users/123
JSON 请求体 json.NewDecoder(r.Body).Decode {"name":"john"}
原始请求体 io.ReadAll(r.Body) 二进制 / XML 等

JSON 解析示例

go

复制代码
var user User
err := json.NewDecoder(r.Body).Decode(&user)

六、完整示例:RESTful API(Go 1.22+)

go

复制代码
package main

import (
    "encoding/json"
    "net/http"
    "strconv"
    "sync"
)

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

var (
    users   = make(map[int]User)
    nextID  = 1
    usersMu sync.RWMutex
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("GET /users", listUsers)
    mux.HandleFunc("POST /users", createUser)
    mux.HandleFunc("GET /users/{id}", getUser)
    mux.HandleFunc("PUT /users/{id}", updateUser)
    mux.HandleFunc("DELETE /users/{id}", deleteUser)
    http.ListenAndServe(":8080", mux)
}
// 各函数实现略(详见原文)

七、常见错误与最佳实践

❌ 常见错误

  • 未关闭响应体
  • 在写入响应体后调用 WriteHeader
  • 忽略错误处理
  • 未设置超时

✅ 最佳实践

  • 重用 HTTP 客户端
  • 使用 Context 控制超时
  • 统一响应格式
  • 输入验证
  • 优雅关闭服务器
优雅关闭示例

go

复制代码
srv := &http.Server{Addr: ":8080", Handler: mux}
go srv.ListenAndServe()

<-quit
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)

八、总结

组件 关键类型/函数 用途
服务端 http.ListenAndServehttp.Server 启动服务
处理器 Handler 接口、HandleFunc 处理请求
请求 *http.Request 获取请求信息
响应 http.ResponseWriter 构建响应
路由 ServeMuxDefaultServeMux 路由分发
参数 URL.Query()FormValue()PathValue() 获取请求参数

Go 1.22+ 亮点

  • 方法匹配
  • 路径通配符
  • 最具体规则

学习建议

  1. 从标准库入手,理解 Handler 接口
  2. 注意 Go 版本差异(1.22 路由增强)
  3. 实践时注重错误处理、超时控制、资源关闭
相关推荐
铭哥的编程日记2 小时前
DNS解析 HTTP TCP/IP ICMP/NAT/NAPT相关知识点
网络协议·tcp/ip·http
ん贤3 小时前
一文读懂 Go-Eino 的 Embedding
开发语言·golang·embedding
cheems952714 小时前
[网络原理]http协议理论基础以及wireshark抓包分析(二)
网络·http·wireshark
cheems952717 小时前
[网络原理]http协议理论基础以及wireshark抓包分析(一)
网络·http·wireshark
AMoon丶17 小时前
Golang--多种数据结构详解
linux·c语言·开发语言·数据结构·c++·后端·golang
牛奶19 小时前
为什么敲几个字母就能访问网站?DNS原理大揭秘
前端·http·dns
牛奶20 小时前
HTTP裸奔,HTTPS穿盔甲——它们有什么区别?
前端·http·https
AI-小柒20 小时前
开发者一站式数据解决方案:通过 DataEyes API 一键配置智能数据采集与分析工具
大数据·人工智能·windows·http·macos
不会写DN1 天前
Golang中实时推送的功臣 - WebSocket
开发语言·后端·golang