
Go HTTP handler 返回 JSON 时为什么浏览器显示乱码或下载文件?
因为默认没设 Content-Type,浏览器不知道这是 JSON,可能当成 text/plain 或直接触发下载。Go 的 http.ServeHTTP 不自动加头,得手动写。
- 必须在
w.Header().Set("Content-Type", "application/json; charset=utf-8"),注意分号和utf-8—— 少了 charset,中文字段可能乱码 - 别用
fmt.Fprintf(w, ...)拼 JSON 字符串,易出错且不安全;统一走json.NewEncoder(w).Encode(...) - 如果用了
log.Fatal(http.ListenAndServe(...)),出错会直接退出,健康检查 API 崩了没人知道;建议用http.Server显式启停,方便后续加超时或优雅关闭
用 json.Marshal 还是 json.NewEncoder?
优先选 json.NewEncoder:它直接写到 http.ResponseWriter(本质是 io.Writer),不占内存、不拼大字符串、自动处理流式错误。
-
json.Marshal先把整个结构体转成[]byte,再w.Write—— 对小响应影响不大,但万一结构体嵌套深、字段多,容易 OOM -
json.NewEncoder(w).Encode(v)是流式编码,边序列化边写,还支持SetEscapeHTML(false)(比如返回带 HTML 的消息字段时避免转义) - 错误处理要立刻判断:
if err := json.NewEncoder(w).Encode(resp); err != nil { return },否则网络中断时 panic 可能被吞掉
健康检查接口该返回什么字段才不算“假阳性”?
只返回 {"status": "ok"} 没用——服务进程活着,但数据库连不上、磁盘快满了、依赖的 Redis 超时了,照样不可用。
- 至少包含
status(整体结果)、checks(各子项明细)、timestamp(便于排查时序问题) - 每个子检查项要有
name、status(pass/fail)、message(如"timeout after 3s"),不要只写"db: ok" - 数据库检查别只
Ping(),加上简单查询(如SELECT 1),否则连接池空闲时也过不了真压测
为什么本地 curl 正常,K8s livenessProbe 却反复重启?
多半是响应超时或状态码不对。K8s 默认只认 200–399 为健康,且默认超时 1 秒,而 Go 默认无读写超时。
立即学习“go语言免费学习笔记(深入)”;
- 确保 handler 里所有操作(DB Ping、HTTP 调依赖服务)都带上下文超时,例如
ctx, cancel := context.WithTimeout(r.Context(), 800*time.Millisecond) - 别在 health handler 里做重试逻辑,livenessProbe 本身会重试,重复重试反而放大雪崩风险
- 返回非
200状态码时,一定要先调w.WriteHeader(http.StatusServiceUnavailable),否则json.NewEncoder会默认写200
健康检查不是加个 endpoint 就完事,关键在「它到底反映了什么」——字段含义、超时控制、错误归因,每一步漏掉一点,线上就少一分确定性。










