etag需严格遵循rfc 7232规范,强校验为"xxx"、弱校验为w/"xxx";应基于响应体内容(如sha256哈希)生成,避免动态字段干扰;go中需手动设置header并校验if-none-match,返回304时必须清空body且仅保留允许头。

Go 里怎么生成标准 ETag
ETag 不是随便拼个字符串就行,得符合 RFC 7232:强校验("xxx")或弱校验(W/"xxx"),且内容需反映资源本质变化。用 md5 或 sha256 哈希响应体最稳妥,但要注意——如果响应体含动态时间戳、随机 ID 或用户相关字段,哈希会变,缓存就失效了。
实操建议:
- 对静态内容(如 JSON API 返回的固定结构数据),用
sha256.Sum256()哈希responseBody字节,再转成 hex 字符串,包裹进双引号:"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - 对 HTML 模板渲染结果,别哈希整个
bytes.Buffer输出——模板里可能有{{.Now}}这种变量,得先剥离或冻结上下文再计算 - 避免用文件修改时间(
os.FileInfo.ModTime())直接当 ETag,它精度低、时区不一致,且不能反映内容真实变更
net/http 中怎么设置和校验 ETag
Go 标准库不自动处理 ETag,得手动读 If-None-Match 请求头、比对、返回 304 Not Modified。很多人直接写 w.WriteHeader(http.StatusNotModified) 就完事,忘了清空 body、删掉其他响应头,导致客户端收到冲突响应。
实操建议:
- 生成 ETag 后,用
w.Header().Set("ETag", etag)设置;注意值必须带引号,"abc"合法,abc不合法 - 校验时用
r.Header.Get("If-None-Match")取值,再用http.EtagMatch()(Go 1.19+)或手动拆分逗号、去掉引号后比对——别自己写字符串==,要支持多个 ETag 和弱匹配(W/"...") - 返回 304 时,**必须清空所有已写入的 response body**(比如你之前调过
json.NewEncoder(w).Encode(...),就得提前判断,别真写进去),且只保留Date、ETag、Vary等允许出现在 304 中的头
gin / echo 等框架里 ETag 怎么开
这些框架默认不开启 ETag,也没提供一键开关。有人翻文档找到 gin.Context.ETag(),结果发现它只是个 getter,不是 setter——这是最容易卡住的地方。
实操建议:
- gin:没内置支持,得自己在 handler 开头算 ETag,用
c.Writer.Header().Set("ETag", ...),再手动检查c.Request.Header.Get("If-None-Match") - echo:同理,
c.Response().Header().Set("ETag", ...),但注意echo.Response的 writer 是包装过的,304 时要调c.NoContent(http.StatusNotModified),而不是直接写状态码 - 别依赖中间件如
gin-contrib/etag——它只对静态文件生效,对 JSON API handler 完全不触发
ETag 和 Last-Modified 能一起用吗
能,但没必要叠 buff。HTTP 规范说客户端收到两者时,优先用 ETag 校验;而服务端如果同时设了两个,反而增加首字节延迟(得读文件 or 计算哈希 + 获取 mtime)。更麻烦的是,Last-Modified 精度只有秒级,同一秒内两次更新,它就判不出变化。
实操建议:
- 纯 API 场景(JSON/XML 返回),只用 ETag,别碰
Last-Modified—— 它对无文件后端意义不大 - 静态文件服务(如
http.FileServer)默认带Last-Modified,若想强制用 ETag,得 wraphttp.FileSystem,重写Open(),在打开时计算哈希并注入 header - 如果必须共存,确保 ETag 值不等于
fmt.Sprintf(`"%x"`, modTime.Unix())这种错误写法——那等于把时间戳当哈希,完全失去校验意义
ETag 的核心就两条:值必须稳定反映内容,校验逻辑必须严格按 RFC 处理引号和弱匹配。多数问题出在“以为设了 header 就完事”,其实漏掉了 304 响应的清理和边界判断。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











