LabHub
学习 学习路径 课程

用 Go 写服务器

只用标准库做一个服务器

在 LabHub 中继续学习

目标

仅使用标准库构建 HTTP 服务器,观察 Go 会强制开发者做什么。在选择框架之前,先确认 net/http 已经提供了哪些能力。

为什么重要

初次使用 Go 的人常说 if err != nil 很烦琐。但这种篇幅不是成本,而是显式性的代价:类型中明确写出了哪一行可能失败,若要忽略错误,也必须明确写出忽略行为。

本实验会让你亲手体会这种代价及其收益,还会直接制造 Go 中真正容易引发事故的问题(goroutine 泄漏、取消未传播)。

环境

由于没有网络,go get 无法运行。本实验只使用标准库,因此不受影响——这反而正是本课程想说明的重点。

go mod init <이름>     모듈 시작
go build -o srv .      빌드
go vet ./...           흔한 실수 찾기
gofmt -l .             포맷이 어긋난 파일 나열

步骤

  1. 初始化模块 → /root/work/gosrv/go.mod
  2. /health 服务器
  3. 将错误作为值返回(用 %w 包装)
  4. errors.Is/As/root/work/gosrv/04-errors.txt
  5. JSON 响应 → /root/work/gosrv/05-json.txt
  6. 通过 context 传播取消 → /root/work/gosrv/06-ctx.txt
  7. goroutine 泄漏 → /root/work/gosrv/07-leak.txt
  8. go vet / gofmt/root/work/gosrv/08-vet.txt

参考

创建模块

初始化模块 → /root/work/gosrv/go.mod

执行 mkdir -p /root/work/gosrv && cd /root/work/gosrv && go mod init labhub.local/gosrv。由于没有网络,无法下载外部包;本实验只使用标准库。生成 go.mod 即可。

一个 HTTP 服务器

/health 服务器

main.go 中使用 net/http 创建 /health,并监听 8080 端口。用 go build -o srv . 构建,再用 ./srv & 启动,然后执行 curl -s localhost:8080/health 验证。无需框架,标准库就已提供这些能力。

将错误作为值返回

将错误作为值返回(用 %w 包装)

创建 parseAge(s string) (int, error),当输入不是数字时返回错误。包装时请像 fmt.Errorf("나이 파싱(%s): %w", s, err) 一样使用 %w。若用 %v 包装,就会丢失原始错误,无法再通过 errors.Is 查询。

查询错误原因

errors.Is/As/root/work/gosrv/04-errors.txt

加入使用 errors.Iserrors.As 判断被包装错误原因的代码,并将输出保存到 /root/work/gosrv/04-errors.txt。目的是亲眼确认可以从包装后的错误中取出原始错误。

返回 JSON

JSON 响应 → /root/work/gosrv/05-json.txt

使用 encoding/json 返回结构体。若不添加字段标签(json:"name"),字段名会保留大写形式,这是 Go 的 export 规则所致。将 curl -s localhost:8080/api | jq . 的结果保存到 /root/work/gosrv/05-json.txt

传播取消信号

通过 context 传播取消 → /root/work/gosrv/06-ctx.txt

创建一个较慢的 handler,监听 r.Context()Done(),使客户端断开时停止工作。用 curl --max-time 1 中断请求,查看服务器日志是否记录了取消。将输出保存到 /root/work/gosrv/06-ctx.txt

观察 goroutine 泄漏

goroutine 泄漏 → /root/work/gosrv/07-leak.txt

故意创建一个会泄漏的 goroutine(向没有接收方的 channel 发送),在前后分别输出 runtime.NumGoroutine(),并保存到 /root/work/gosrv/07-leak.txt。数量增加后不再下降,就表示发生了泄漏。

先询问工具

go vet / gofmt/root/work/gosrv/08-vet.txt

运行 go vet ./...gofmt -l .,将结果保存到 /root/work/gosrv/08-vet.txt。两者都没有输出即表示通过。Go 不争论格式:gofmt 就是标准答案,因此代码评审中不再需要讨论格式。