在 Go 的 Web 编程体系中,http 包是最基础也最核心的标准库。其中 Handler 和 ServerMux 构成了整个 HTTP 请求处理流程的关键抽象。理解它们的工作原理,有助于我们更从容地应对高并发场景下的网络编程。
为什么需要 Handler 与 ServerMux
Web 服务器本质上要解决三个问题:监听端口接收请求、根据路径找到对应逻辑、执行逻辑并返回响应。在 Go 中,这三个职责被清晰地拆分给了不同的组件:
| 问题 | Go 中的抽象 |
|---|---|
| 接收请求 | http.Server |
| 路由分发 | ServeMux |
| 业务处理 | Handler |
简单来说,Handler 负责具体做什么,而 ServerMux 负责找谁来做。
建立连接
接收请求主要依赖 http.Server。与传统的阻塞式 IO 不同,Go 为了实现高并发和高性能,底层使用 goroutine 来处理每个连接的读写事件。这意味着每个请求都能保持独立,互不阻塞,从而高效响应网络事件。
在等待客户端请求时,底层的实现逻辑大致如下:
c, err := srv.newConn(rw)
if err != nil {
continue
}
go c.serve()
可以看到,每次客户端请求都会创建一个 Conn 对象,其中保存了该次请求的信息,随后传递给对应的 handler。这样保证了每个请求上下文的独立性。
那么,Go 是如何让 Web 服务运行起来的呢?主要通过 ListenAndServe 函数。这个函数底层做了三件关键的事情:
- 创建 TCP Listener
- 进入 Accept 循环
- 为每个连接启动 goroutine
http.ListenAndServe(":8080", nil)
这实际上等价于显式初始化一个 Server 对象:
server := &http.Server{
Addr: ":8080",
Handler: http.DefaultServeMux,
}
server.ListenAndServe()
这是一个阻塞函数,启动后会持续监听请求,直到程序被中断。
路由分发
ServeMux 是什么
ServeMux 是 Go 标准库提供的 HTTP 请求多路复用器,它的作用是根据请求路径,选择一个合适的 Handler 来处理请求。
ServeMux 底层结构
type ServeMux struct {
mu sync.RWMutex // 锁,用于并发保护
m map[string]muxEntry
hosts
}
muxEntry {
explicit
h Handler
pattern
}

