目标与背景
目标
实现一个自定义的 HTTP 处理器(Handler),让它能够根据不同的 URL 路径作出不同的响应。
背景知识
- Go 的
net/http
包定义了一个接口Handler
,只要求实现一个方法:ServeHTTP(ResponseWriter, *Request)
。(http.Handler 接口非常简单,只包含一个 ServeHTTP 方法)
只要你的类型实现了这个方法,就可以把它作为 HTTP 服务器的请求处理器。 - 接口与多态:在 Go 中,接口是一种约定,只要一个类型实现了接口中的所有方法,它就被认为实现了该接口。
- 服务器启动:使用 http.ListenAndServe 启动 HTTP 服务器,这个函数需要一个地址和一个实现了 Handler 接口的对象。服务器会自动调用你提供的 ServeHTTP 方法来处理每个请求。
代码编写
- 创建项目文件
新建一个文件夹,例如 go-handler-demo。
在该文件夹中创建一个名为 main.go 的文件。 - 编写代码骨架
声明包名 package main,导入需要的包(fmt、log、net/http)。
写一个空的 main 函数。 - 定义自定义 Handler
type Engine struct {
}
这里还没有额外的状态,但后续可以扩展,比如添加路由表、中间件等功能。
// 实现 ServeHTTP 方法,让 Engine 满足 http.Handler 接口
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
switch req.URL.Path {
case "/":
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
case "/hello":
for k, v := range req.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
default:
fmt.Fprintf(w, "404 Not Found: %\n", req.URL)
}
}
只要你在 Engine 上定义了 ServeHTTP(w http.ResponseWriter, req *http.Request) 方法,Engine 就实现了 http.Handler 接口。
- 在 main 函数中使用自定义 Handler
func main() {
// 创建一个 Engine 实例
engine := new(Engine)
// 将 engine 作为 http.ListenAndServe 的处理器传入
log.Fatal(http.ListenAndServe(":9999", engine))
}
- 创建一个 Engine 的实例。可以使用 new(Engine) 或 &Engine{}。
- 所有请求都会传递给engine的 ServeHTTP 方法
总结
理解Go 的 http.Handler 接口
总之:你只需实现 ServeHTTP 方法,就能让你的类型成为一个 HTTP 请求处理器。
在 Go 标准库中,HTTP 服务的核心接口是 http.Handler,其定义非常简单
package http
type Handler interface {
ServeHTTP(w ResponseWriter, r *Request)
}
- ServeHTTP 方法:只要一个类型实现了这个方法,它就被视为实现了 http.Handler 接口。因此,当你把一个实现了该接口的实例传入 http.ListenAndServe 时,所有的 HTTP 请求都会由这个实例的 ServeHTTP 方法来处理。
- 这种设计让我们可以完全控制请求的处理流程。你可以把所有请求都集中到一个入口,然后在这里添加统一的逻辑,比如日志记录、错误处理、路由分发等等。
- 对比:在之前的例子中,我们使用 http.HandleFunc 为每个路由单独注册处理函数。
这里通过实现 ServeHTTP,所有请求都进入了 Engine,形成了一个统一的入口。
- 对比:在之前的例子中,我们使用 http.HandleFunc 为每个路由单独注册处理函数。
解耦与灵活扩展
- 后续你可以在 Engine 中增加一个路由映射表,让不同的 URL 分发到不同的处理函数,实现更灵活的路由控制(比如动态路由、路由组等)。
- 将所有请求都交给 Engine 统一处理,为日后扩展功能(如路由映射、中间件、日志记录)打下基础。
充分利用接口的多态特性
Go 的 http.ListenAndServe 函数接受的第二个参数只要实现了 http.Handler 接口就行