知其然,知其所以然
Gin 框架内部原理 2026-10-11

WriteHeader 之后再改 header 会怎样

在 Gin v1.12.0 里实测 WriteHeader 之后再改 header:第一次写之前设的头(同一个键以最后一次为准)会发出,写出之后设的头客户端看不到;不设 Content-Type 时由 Go 在第一次写时嗅探,JSON 字符串被判成 text/plain;绕过 Gin 在底层写两次会触发 superfluous 日志;要在正文之后发的头只能用 Trailer。

Gin 响应头 WriteHeader Trailer Content-Type Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

绑定 tag:form、json、uri、header、query

在 Gin v1.12.0 里实测绑定 tag:ShouldBindQuery 读的是 form 标签而不是 query;uri、header、json 各读各的;没有 tag 时 key 是区分大小写的字段名;ShouldBind 对 GET 永远用 form,带 JSON body 的 GET 被忽略且没有错误;带 form 标签的结构体字段按 JSON 解码。

Gin 参数绑定 binding tag form json uri header Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

validator 常用规则与错误信息

在 Gin v1.12.0(validator v10.30.1)里实测校验规则:tag 名是 binding;一份全不合格的请求报出 11 项 FieldError;ShouldBindJSON 返回三类错误;min/max 对字符串按字符数、数字比数值、切片比个数;嵌套结构体自动校验,切片和 map 的元素要写 dive。

Gin validator 参数校验 binding required dive Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

自定义校验器 RegisterValidation

在 Gin v1.12.0 里实测自定义校验器:从 binding.Validator.Engine() 拿到 *validator.Validate 注册规则、别名、带参数的规则和结构体级校验;RegisterTagNameFunc 必须在类型第一次校验之前;使用未注册的规则名要到第一次校验时才 panic;binding.Validator 可以整体替换或设为 nil。

Gin validator 自定义校验 RegisterValidation StructLevel Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

required 对零值的陷阱与指针

在 Gin v1.12.0 里实测 required 对零值的陷阱:值类型字段传 0 / 空串 / false 都当作没传,指针字段传零值则通过、不传或 null 才失败;空切片 [] 与全空格字符串通过;time.Time 零值失败;嵌套结构体自身不检查;查询串里缺失的键与 0 都是零值。

Gin validator required 零值 指针 omitempty Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

绑定 time.Time、切片、嵌套结构

在 Gin v1.12.0 里实测 time.Time、切片、嵌套类型的绑定:time_format / time_utc / time_location / unix 的时区结果(设进程时区为 America/New_York);查询串里的加号变空格;?multi=1,2,3 必须写 collection_format:"csv" 才能拆开;类型转换错误的原文;自定义类型实现 UnmarshalParam。

Gin 参数绑定 time.Time 切片 collection_format Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

JSON 绑定:DisallowUnknownFields 与 UseNumber

在 Gin v1.12.0 里实测 JSON 绑定的严格程度:默认忽略多余字段、键不区分大小写、末尾的垃圾内容也通过;binding.EnableDecoderDisallowUnknownFields 让未知字段(含嵌套)报错但它是全局开关;UseNumber 让 any 里的大整数不丢精度(9007199254740993 默认被解成 …992)。

Gin JSON绑定 DisallowUnknownFields UseNumber Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

多余字段与缺失字段的行为

在 Gin v1.12.0 里实测多余字段与缺失字段:缺失字段保持预填值、传了零值会覆盖、null 对非指针字段是空操作;预填的 map 合并、切片替换、非 nil 指针原地改写;类型错误不会中止解码;用 *T、RawMessage、自定义 Opt[T] 区分“没传 / null / 零值”。

Gin JSON绑定 缺失字段 多余字段 PATCH Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

文件上传:MaxMultipartMemory 与临时文件

在 Gin v1.12.0 里实测文件上传的内存限制:MaxMultipartMemory 默认 32 MiB,只决定放内存还是落磁盘,不限制总大小;5 MiB 文件在 1 MiB 限制下变成临时文件、请求结束后被删除;40 MiB 文件在 64 MiB 限制下累计分配 128 MiB(约 3 倍);不加 MaxBytesReader 时 200 MiB 照收。

Gin 文件上传 MaxMultipartMemory multipart MaxBytesReader Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

多文件上传

在 Gin v1.12.0 里实测多文件上传:FormFile 只返回同名字段的第一个文件,MultipartForm().File 返回全部;[]*multipart.FileHeader 可绑定到结构体;文件名先经 filepath.Base 但反斜杠原样保留;SaveUploadedFile 会 MkdirAll 并把已有目录 chmod 成 0750;一个请求最多 1000 个 part。

Gin 文件上传 多文件 SaveUploadedFile multipart Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

JSON、PureJSON、AsciiJSON、SecureJSON 的输出差别

在 Gin v1.12.0 里实测 JSON 的六种渲染:同一份数据的输出字节与 Content-Type;PureJSON 不转义 HTML 字符(68 字节对 92 字节)、末尾多一个换行;AsciiJSON 把 emoji 写成非法的 \u1f600(标准解析器读回 "ὠ0");SecureJSON 只给顶层数组加前缀;JSONP 的 callback 只做 JS 转义;序列化失败时是 200 加空正文。

Gin JSON渲染 PureJSON AsciiJSON SecureJSON JSONP Go 真实验证 动画演示
Gin 框架内部原理 2026-10-11

Negotiate:按 Accept 选择响应格式

在 Gin v1.12.0 里实测内容协商:NegotiateFormat 丢弃 q 值,按 Accept 里的出现顺序逐字符前缀匹配(区分大小写),所以 application/json;q=0 仍会被选中;application/yaml 对不上 application/x-yaml 会 406;没有匹配时 Negotiate 返回 406 并把错误记入 c.Errors;不传 Offered 会 panic。

Gin 内容协商 Negotiate Accept 406 Go 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号