Web 服务器与 REST API — 用标准库 net/http 造一座 API¶
这一章讲什么: 不用任何框架,用 Go 标准库的
net/http造出生产可用的 REST API:请求怎么流进来、路由怎么分发、中间件怎么一层层包、JSON 怎么进出自如、 错误怎么统一成信封。 它在全书链条里的位置: 第 06 章的 repository 在这里被包进 HTTP handler—— handler 取r.Context()传下去,优雅关闭原样接用。读完这章,前两章的下半身 就有了上半身。 第 10 章再把这座 API 装进容器。 主线例子(贯穿本章): 原书的「图书 API」——GET /books/{id}取书、POST /books建书、PATCH /books/{id}改书。从最小服务器开始逐节加件, 最后中间件链 + JSON 信封 + AI 生成脚手架走一遍。
1. 顶层全景:一个请求的一生¶
客户端 ──► TCP 监听(:8080)──► 每个连接一个 goroutine 解析 HTTP
──► ServeMux 按最长前缀匹配路由 ──► 中间件链(洋葱,从外到内)
──► handler:读 r.Body → 解码 JSON → 调 service/repo → 编码响应
──► 中间件收尾(记日志、补安全头)──► 写回客户端
三样核心抽象,全章都围着它们转1:
| 抽象 | 是什么 | 记住的一句话 |
|---|---|---|
http.Request |
进来的请求全装在里面:方法、URL、头、cookie、body 流、Context() |
body 是流,可大可小 |
http.ResponseWriter |
写回头部的接口:状态码、响应头、body 字节 | 接口虽小,内部管着缓冲和连接复用 |
http.Handler |
只有一个方法的接口:ServeHTTP(w, r) |
任何东西实现了它就能当 handler |
函数型 handler 靠适配器 http.HandlerFunc 变身为 Handler——
这是「第 02 章的接口 + 第 03 章的函数类型」在 HTTP 里的第一次实战2。
并发不用你管: ListenAndServe 接受连接后,每个请求自动开一个 goroutine——
阻塞一个请求不会阻塞整个服务,这正是第 05 章机制的天然用武之地3。
最小服务器(原书例,五行核心):
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Welcome to the Go Web Server!")
})
http.ListenAndServe(":8080", nil)
}
nil 那个参数是默认的多路复用器 http.DefaultServeMux——全局状态,
稍大的项目就该换成自己 http.NewServeMux()4。
2. 生产配置:别把裸 ListenAndServe 开上线¶
http.Server 结构体暴露关键旋钮5:
server := &http.Server{
Addr: ":8080",
Handler: myMux,
ReadTimeout: 5 * time.Second, // 读请求(含 body)的预算
WriteTimeout: 10 * time.Second, // 写响应的预算
IdleTimeout: 120 * time.Second, // keep-alive 闲连接的寿命
MaxHeaderBytes: 1 << 20, // 请求头上限 1MB
}
原书明说:生产环境配这些字段是必需——防慢客户端拖死连接、防 header 炸弹、
防资源耗尽5。1 << 20 是位运算写法,等于 1MB(2 的 20 次方)。
3. 路由:最长前缀匹配,没有参数路由¶
ServeMux 的规则简单到可以背下来6:
- 注册
"/users"—— 精确匹配,只有/users; - 注册
"/users/"(尾斜杠)—— 子树匹配:/users/42、/users/42/orders全中; - 多条命中时,最长前缀赢:
/users/create比/users/长,优先。
标准库不支持 /users/:id 这种参数路由——要么在 handler 里自己从路径里切,
要么引第三方路由(Chi、Gorilla Mux);很多高吞吐系统干脆设计成可预测的嵌套路径,
纯标准库跑生产7。
方法分发显式写在 handler 里(GET 取、POST 建、PUT 全替、PATCH 部分改、DELETE 删),
default 分支回 405 Method Not Allowed8。原书还给了个可复用的小工具:
MethodRouter(map[string]http.HandlerFunc{...}),把方法→handler 的映射表
变成一段中间件9。
模块化组织: 各域自己注册路由,main 只负责组装10:
// internal/user/routes.go
func RegisterUserRoutes(mux *http.ServeMux) {
mux.HandleFunc("/users", listUsers)
mux.HandleFunc("/users/", userHandler)
}
// main.go
mux := http.NewServeMux()
user.RegisterUserRoutes(mux)
4. 依赖注入与中间件:闭包的两大用途¶
闭包注依赖(第 03 章匿名函数的回响):handler 工厂收 repository、吐 handler, 全局变量退场11:
func UserHandler(repo UserRepository) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
user, err := repo.Find(id)
if err != nil {
http.Error(w, "User not found", http.StatusNotFound)
return
}
fmt.Fprintf(w, "User: %s", user.Name)
}
}
mux.HandleFunc("/users/details", UserHandler(userRepo))
中间件 = 装饰器模式(含义:给一个对象外面包一层,加行为不改本体)。
签名一眼定型:func(http.Handler) http.Handler——收一个 handler,还一个 handler12:
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Request: %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}
链构造函数把多层串起来(注意倒序包裹——先传的包在最外层)13:
type Middleware func(http.Handler) http.Handler
func Chain(h http.Handler, mws ...Middleware) http.Handler {
for i := len(mws) - 1; i >= 0; i-- {
h = mws[i](h)
}
return h
}
四个生产必备中间件(原书清单)14:
| 中间件 | 干什么 | 关键点 |
|---|---|---|
| Trace/Logging | 每个请求一个 trace ID,写进 ctx 和日志 | r.WithContext(ctx) 传下去 |
| Recover | 兜住 handler 里的 panic,回 500 | defer + recover,第 04 章的边界拦截落地 |
| Auth | 验 API key / JWT | 不通过直接 401,不调 next |
| Security Headers | 补 X-Frame-Options 等 |
先设头再调 next |
想改响应(比如记状态码)? 包一层自定义 ResponseWriter:内嵌接口再覆写
WriteHeader,拦下状态码存下来——原书称「response interception」15。
性能提醒: 每层中间件都是每次请求多几次函数调用;重的活别放中间件里, 昂贵的能力只挂在需要的路由组上16。
4.6 把图书 API 装配成洋葱:一条链的完整顺序¶
第 4 节的零件在这收成一条真实装配线。顺序的口诀:Recover 在最外层 ( panic 兜底要罩住所有人)、Trace 紧随其后(后面的层都能用 trace ID)、 Auth 贴着业务(认证过了才轮到干活):
final := http.HandlerFunc(updateBookHandler)
handler := Chain(final,
RecoverMiddleware, // ① 最外:任何 panic 都在这被拦成 500
TraceMiddleware, // ② 每个请求一个 trace ID,写进 ctx 和日志
AuthMiddleware, // ③ 验不过 401,不进业务
)
mux := http.NewServeMux()
mux.Handle("/books/", handler)
srv := &http.Server{Addr: ":8080", Handler: mux, ReadTimeout: 5 * time.Second}
srv.ListenAndServe()
一个请求穿行的顺序(数字即先后):
进 ──► Recover(挂上兜底) ──► Trace(发 ID) ──► Auth(验钥匙)
──► updateBookHandler(干活) ──► 返回时各层收尾:Auth 无活,Trace 记一行,Recover 无 panic
两个容易装反的地方:
- Auth 别放最外层:未认证的探测流量也配拥有 trace ID 和 panic 兜底, 而且认证逻辑自己 panic 时,外层得有人兜;
- Trace 要在 Auth 之前:否则 401 的请求在日志里消失,你在排查「谁老在撞门」时 会两眼一抹黑。
4.7 性能账:中间件到底花多少¶
原书的提醒量化一下:每层中间件是每请求两次函数调用(进、出各一次)加少量分配。 一次请求本来的成本是微秒级网络 + 毫秒级业务,中间件的纳秒级开销可以忽略; 真正要警惕的是两种自己造成的开销:在中间件里做重 I/O(比如同步写日志文件—— 第 03 章的 bufio 纪律在这里同样适用),和给不需要的路由也挂上全套链 (内部健康检查端点挂 Auth 就是给自己找事)。
5. JSON:编码解码、验证与安全清单¶
两核心函数:json.Marshal(Go 值 → JSON 字节)与 json.Unmarshal(JSON → Go 值);
struct tag(json:"name" 那种反引号标注)指定字段名和选项17。
读请求体用 json.NewDecoder(r.Body) 直接吃流——增量解析,不吃大内存;
严格模式加一行 decoder.DisallowUnknownFields(),客户端多传字段直接拒
(防版本漂移和拼写错)18:
var input CreateUserRequest
decoder := json.NewDecoder(r.Body)
decoder.DisallowUnknownFields()
if err := decoder.Decode(&input); err != nil {
writeError(w, http.StatusBadRequest, "invalid JSON: "+err.Error())
return
}
JSON 解码过关 ≠ 业务合法——空邮箱、负年龄照样能解码。手工检查或上
go-playground/validator 库19。
写响应:w.Header().Set("Content-Type", "application/json") 先行,
json.NewEncoder(w).Encode(v) 流式写出——头必须先于 body,输出开始了
就再改不了头20。tag 技巧三个:omitempty(零值省略)、json:"-"(完全不导出)、
price,string(数字按字符串编——对接老式系统常用)21。大数据集可以手工
逐条 Encode 拼数组括号,边算边发22。
安全三条(原书名列)23:
- 限 body 大小:
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)——1MB 封顶, 防超大 body 打爆内存; - 未知 JSON 别用
interface{}——用map[string]any或json.RawMessage, 防类型混乱; - 输出要消毒——用户给的字符串进下游系统(数据库、HTML)前都要过一遍。
5.6 自定义 Marshaler:时间的标准格式¶
struct tag 之外,JSON 行为还能整体接管:实现 MarshalJSON/UnmarshalJSON
两个方法,编码器就听你的。原书的例子是把时间统一成 RFC 3339 格式
(如 2026-10-19T08:30:00Z,一种国际通行的日期时间写法):
type JSONTime time.Time
func (t JSONTime) MarshalJSON() ([]byte, error) {
ts := time.Time(t).Format(time.RFC3339)
return []byte(`"` + ts + `"`), nil
}
用处三件事:时间/货币等格式统一、敏感字段脱敏(Marshal 时打码)、
旧系统兼容(对方要的形状和 Go 默认不一样)。这是「tag 不够用」时的下一层,
多数项目一辈子用不到,用到时记住接口名 json.Marshaler。
5.7 静态文件与 WebSocket 之外的常规缺口¶
本章没覆盖但每个项目都会撞的:静态文件服务(原书给了两行:
http.FileServer + http.StripPrefix);表单与 multipart;
以及 HTTP/2 服务端推送这类进阶特性。本章的 handler/中间件模型对它们同样适用——
新特性的学习成本不在「又一套 API」,而在「同一个模型里的新参数」。
6. 错误处理:信封、映射表与 panic 兜底¶
错误分类(4xx 客户端 / 5xx 服务器 / ctx 驱动的超时与取消 / 业务验证), 每个请求相互隔离,一处失败不传染24。统一信封:
type ErrorResponse struct {
Error string `json:"error"`
Message string `json:"message"`
}
func writeError(w http.ResponseWriter, status int, msg string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(ErrorResponse{Error: http.StatusText(status), Message: msg})
}
全服务一个形状——客户端可预期、文档可依赖、AI 工具也能据此分析25。
错误映射表(进阶):内部错误不直接吐给客户端,而是映射——ErrUserExists →
409 Conflict、ErrNotFound → 404。细节留在服务端日志,客户端只拿该拿的26。
ctx 错误单独认:errors.Is(err, context.DeadlineExceeded) → 回 504
Gateway Timeout;context.Canceled → 客户端断了,直接收工不白算27。
panic 兜底中间件(生产必配,原书原话:「vital for production reliability」):
func RecoverMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {
log.Printf("panic: %v", rec)
writeError(w, http.StatusInternalServerError, "internal server error")
}
}()
next.ServeHTTP(w, r)
})
}
没有它,一个 nil 指针就能让整个进程的请求带着栈轨迹裸奔到 stderr28。
7. 主线例子走一遍:图书 API 的三次生长¶
第一次(脚手架): GET /books/{id} + POST /books,内存 map 当库,
json.Decoder 进、json.NewEncoder 出,201 Created 表示建成29。
第二次(补丁): PATCH /books/{id} 只改提供的字段——请求结构用指针字段
*string,nil 表示「这字段没提」,非 nil 才覆盖。这是「部分更新」的标准形状30。
第三次(工业化): 包上中间件链 Chain(final, Logging, Recover, Auth),
错误全走 writeError 信封,启动换 http.Server 带超时,退出接第 06 章的
优雅关闭。
8. AI 生成 API 端点(辅线):提示、产物与四条验收¶
原书演示了五步 AI 协作:描述行为 → 生成 CRUD 脚手架 → 追加验证 → 统一错误格式 → 生成请求/响应模型。生成的 PATCH handler 质量不错 (指针字段处理是对的),但原书紧接着给的四条验收才是重点31:
- 验证 AI 的输出:查漏掉的错误处理、不安全模式、错误状态码、低效数据结构;
- 套你自己的架构:AI 不知道你的 repository 模式、领域模型、框架偏好—— 提示里就写清「用 chi」「错误格式长这样」;
- 提示要精确:高质量提示换高质量代码;
- AI 是协作者不是替代者:架构决策、代码评审、安全与性能考虑,一样不能让渡。
一个具体的审查锚点:AI 爱用内存 map + 包级变量当存储(图书 API 就是), 这在脚手架里可爱,上生产前必须换成第 06 章的 repository + 数据库—— AI 生成的第一版永远停在「能跑」,「能活」要你自己补。
9. 框架一瞥:Gin 的位置¶
原书在介绍处点名 Gin:基于 net/http、radix tree(基数树,一种高效前缀匹配的
数据结构)路由的高性能框架,省样板、速度快32。本章的选择是「先标准库,
懂原理后再框架」——框架的底层仍是本章的 handler/中间件模型(Chi、Echo 同),
学会本章,任何 Go 框架对你都是薄皮。
10. 作者的判断与证据¶
硬事实: 三抽象、生命周期七步、最长前缀规则、无参数路由、http.Server 字段语义、
JSON 两函数与 tag 选项、MaxBytesReader——全部标准库行为,可写代码当场验证1623。
经验主张: 「生产必配 Recover」「标准库够用到很大规模」「AI 产物需四验收」——
社区共识与工程常识,无对照数据2831。
11. 边界与局限¶
- 只讲了 JSON:表单、multipart、XML、gRPC 的入口都不在本章(gRPC 要到第 10 章露脸)。
- 路由的「自己解析路径参数」没有给出健壮工具函数,生产项目多半还是引入 Chi—— 这半步留白读者要自补。
- 测试没展开:httptest 包能让 handler 单测不写 socket,本章没教。
- CORS、限流只在结论里列了名,没实现——第 10 章也不补,属真实留白。
12. 可带走的¶
- 三抽象:
Request(进)/ResponseWriter(出)/Handler(ServeHTTP一个方法)。 - 每请求一个 goroutine,并发内置;裸
ListenAndServe只配演示。 - 生产
http.Server四旋钮:Read/Write/Idle 超时 + header 上限。 - ServeMux:精确 vs 子树(尾斜杠),最长前缀赢;没有
:id参数路由。 - 闭包注依赖、工厂产 handler——全局变量的解药。
- 中间件 =
func(http.Handler) http.Handler;Chain 倒序包裹。 - 生产四件:Trace/Logging、Recover、Auth、Security Headers。
- JSON:Decoder 吃流 + DisallowUnknownFields;tag 三技巧;头先于 body。
- 安全三件套:MaxBytesReader 限 1MB、别用 interface{} 接未知 JSON、输出消毒。
- 错误信封统一全服务;内部错误用映射表翻成状态码,细节留服务端。
- ctx 两错误认亲:DeadlineExceeded → 504,Canceled → 安静收工。
- AI 生成端点后过四验收;它给「能跑」,你给「能活」。
13. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 三核心抽象 | 7. Web Server and REST API Development | text/17-ch07-7-web-server-and-rest-api-development.txt:74(搜「Core Abstractions」) |
| 服务器生命周期七步 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:125(搜「HTTP Server Lifecycle」) |
| 每请求一个 goroutine | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:191(搜「Concurrency is Built-In」) |
| 最小服务器 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:230(搜「Minimal Server」) |
| http.Server 生产配置 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:286(搜「Custom HTTP Server Struct」) |
| ServeMux 与最长前缀 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:400(搜「The Role of ServeMux」) |
| 无参数路由 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:436(搜「parameterized routes」) |
| 闭包注依赖 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:488(搜「Closures to Capture」) |
| MethodRouter | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:507(搜「Reusable Method Routers」) |
| 中间件基本结构 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:565(搜「Basic Middleware Structure」) |
| Chain 倒序包裹 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:586(搜「Middleware Chain」) |
| 四个常用中间件 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:611(搜「Logging and Request Tracing」);Recover 见 :626 |
| ResponseWriter 包装 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:662(搜「Response Interception」) |
| JSON 解码与严格模式 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:701(搜「encoding/json」);DisallowUnknownFields 见 :749 |
| JSON 安全三件套 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:849(搜「Security Considerations」) |
| 结构化错误信封 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:918(搜「Structural Error Responses」) |
| 错误映射表 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:986(搜「mapping table」) |
| ctx 错误认亲 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:1020(搜「Context-Aware Error Handling」) |
| AI 生成 CRUD 全流程 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:1070(搜「AI-Assisted Generation」);PATCH 例见 :1209 |
| 四验收 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:1253(搜「Best Practices When Using AI」) |
| Gin 一瞥 | 同上 | text/17-ch07-7-web-server-and-rest-api-development.txt:204(搜「radix tree」) |
-
出处:「7. Web Server and REST API Development」第 74–123 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:74,搜「Core Abstractions」)。 ↩↩ -
出处:同章第 111–123 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:111,搜「http.Handler」;HandlerFunc 适配器见 :117)。 ↩ -
出处:同章第 125–141 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:125,搜「HTTP Server Lifecycle」;「each request is handled in its own goroutine」见 :139)。 ↩ -
出处:同章第 311–327 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:311,搜「Default Multiplexer versus Custom」)。 ↩ -
出处:同章第 286–309 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:286,搜「Custom HTTP Server Struct」;「essential to prevent slow clients」见 :308)。 ↩↩ -
出处:同章第 400–418 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:400,搜「The Role of ServeMux」;最长前缀见 :412)。 ↩↩ -
出处:同章第 436–440 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:436,搜「parameterized routes」)。 ↩ -
出处:同章第 441–467 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:441,搜「Method-Specific Handling」)。 ↩ -
出处:同章第 507–528 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:507,搜「Reusable Method Routers」)。 ↩ -
出处:同章第 469–486 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:469,搜「Organizing Routes」)。 ↩ -
出处:同章第 488–505 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:488,搜「Closures to Capture Handler Dependencies」)。 ↩ -
出处:同章第 549–579 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:550,搜「Middleware stands crucial」;装饰器模式「mirrors the decorator pattern」见 :562)。 ↩ -
出处:同章第 581–604 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:581,搜「Composable Middleware Chains」;「reverse iteration」见 :602)。 ↩ -
出处:同章第 606–699 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:606,搜「Common Middleware Patterns」;Trace 见 :615,Recover 见 :626,Auth 见 :644,Security Headers 见 :667)。 ↩ -
出处:同章第 662–686 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:662,搜「Response Interception」;状态码包装见 :677)。 ↩ -
出处:同章第 688–699 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:688,搜「Middleware Performance Considerations」)。 ↩ -
出处:同章第 701–726 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:701,搜「encoding/json」;tag 示例见 :714)。 ↩ -
出处:同章第 727–753 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:732,搜「Reading JSON」;DisallowUnknownFields 见 :750)。 ↩ -
出处:同章第 754–771 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:755,搜「domain-level validation」)。 ↩ -
出处:同章第 772–787 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:776,搜「Basic JSON Response Example」;「does not write headers after writing body」见 :785)。 ↩ -
出处:同章第 788–805 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:788,搜「Struct tags allow extensive control」;json:"-"见 :794)。 ↩ -
出处:同章第 806–826 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:807,搜「JSON streaming」)。 ↩ -
出处:同章第 849–862 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:849,搜「Security Considerations When Handling JSON」)。 ↩↩ -
出处:同章第 882–916 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:882,搜「Error Handling in Web Servers」;四类错误见 :901)。 ↩ -
出处:同章第 918–943 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:918,搜「Structural Error Responses」)。 ↩ -
出处:同章第 985–991 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:986,搜「mapping table」;409/404 映射见 :987)。 ↩ -
出处:同章第 1020–1037 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:1020,搜「Context-Aware Error Handling」)。 ↩ -
出处:同章第 999–1019 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:999,搜「Panic Recovery」;「vital for production reliability」见 :643)。 ↩↩ -
出处:同章第 1101–1163 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:1101,搜「Basic CRUD Endpoint」)。图书 API 代码为原书完整示例。 ↩ -
出处:同章第 1209–1251 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:1209,搜「Complete Endpoint Flows」)。指针字段补丁模式见 :1230。 ↩ -
出处:同章第 1253–1280 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:60,搜「Best Practices When Using AI for Endpoint Generation」)。 ↩↩ -
出处:同章第 200–204 段(
text/17-ch07-7-web-server-and-rest-api-development.txt:200,搜「Gin」)。 ↩