http.Handler 接口
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 77 课,共 107 课。
http.Handler 接口是 Go Web 服务器架构的基础。它定义了如何处理 HTTP 请求,任何实现了该接口的类型都可以处理 Web 请求。
这个接口非常简单:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}任何具有 ServeHTTP 方法的类型都可以处理 HTTP 请求。下面是一个自定义处理器:
type GreetHandler struct {
Greeting string
}
func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}你可以将这个处理器直接用于服务器:
handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)对于更简单的情况,Go 提供了 http.HandlerFunc,这是一种可以将普通函数转换为处理器的类型:
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
http.Handle("/hello", http.HandlerFunc(hello))当你意识到处理器可以包装其他处理器时,就会明白这个接口的强大之处。这样就能实现中间件模式,无需修改原始处理器逻辑,就可以添加日志记录、身份验证或其他横切关注点。
挑战
简单让我们来构建一个简单的 HTTP 处理器系统,模拟 Web 请求的处理过程!由于我们无法在这个环境中运行真正的 HTTP 服务器,你将创建实现 http.Handler 接口的处理器,并通过操作模拟的请求和响应对象来展示它们如何处理请求。
你要将代码分成两个文件:
handlers.go:定义自定义 HTTP 处理器。创建一个
MockResponseWriter结构体,用于捕获原本会写入 HTTP 响应的内容。它应将响应正文存储为字符串,并实现一个Write(data []byte) (int, error)方法,将数据追加到正文中。添加一个Body() string方法,用于获取累积的响应内容。创建一个
MockRequest结构体,其中包含Path和Method字符串字段,用来模拟 HTTP 请求。现在,创建两个遵循
http.Handler接口模式的处理器结构体(它们包含一个ServeHTTP方法,该方法接收*MockResponseWriter和*MockRequest):WelcomeHandler,包含一个Message字段,写入消息,后面接上请求路径MethodHandler,根据请求方法写入不同的响应:GET 对应"Fetching data",POST 对应"Creating resource",其他方法对应"Method not supported"
main.go:通过处理器处理请求。读取处理器类型(
welcome或method),然后读取请求详情。对于 welcome 处理器,还要读取欢迎消息。创建相应的处理器,构建一个模拟请求,并调用
ServeHTTP进行处理。打印响应正文。
将提供以下输入:
- 第 1 行:处理器类型(
welcome或method) - 第 2 行:请求路径
- 第 3 行:请求方法
- 第 4 行(仅适用于 welcome):欢迎消息
例如,给定以下输入:
welcome
/home
GET
Hello from输出应为:
Hello from /home再例如,给定以下输入:
method
/api/users
POST输出应为:
Creating resource再例如,给定以下输入:
method
/api/data
GET输出应为:
Fetching data再例如,给定以下输入:
method
/api/items
DELETE输出应为:
Method not supported这个挑战展示了 http.Handler 接口的核心概念:任何包含 ServeHTTP 方法的类型都可以处理请求。在实际应用中,http.ResponseWriter 和 *http.Request 来自 Go 标准库,但实现处理器的模式完全相同。
亲手试试
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 读取处理器类型
scanner.Scan()
handlerType := scanner.Text()
// 读取请求路径
scanner.Scan()
path := scanner.Text()
// 读取请求方法
scanner.Scan()
method := scanner.Text()
// 创建模拟请求
request := &MockRequest{
Path: path,
Method: method,
}
// 创建模拟响应写入器
response := &MockResponseWriter{}
// TODO:根据 handlerType 创建对应的处理器
// 如果 handlerType 是 "welcome",读取欢迎消息并创建 WelcomeHandler
// 如果 handlerType 是 "method",创建 MethodHandler
// 用 response 和 request 调用处理器的 ServeHTTP 方法
if handlerType == "welcome" {
scanner.Scan()
message := scanner.Text()
// TODO:使用消息创建 WelcomeHandler,并调用 ServeHTTP
_ = message // 实现时删除这一行
} else if handlerType == "method" {
// TODO:创建 MethodHandler 并调用 ServeHTTP
}
// 打印响应体
fmt.Println(response.Body())
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Go 在线编译器