Menu
CoddyTech

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))

当你意识到处理器可以包装其他处理器时,就会明白这个接口的强大之处。这样就能实现中间件模式,无需修改原始处理器逻辑,就可以添加日志记录、身份验证或其他横切关注点。

challenge icon

挑战

简单

让我们来构建一个简单的 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())
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Go 在线编译器