// probe.go — serveHealth /healthz 已注册探测(V3 arch-review D-1 修复辅助)。 package main import "net/http" // muxPatternRegistered 探测 ServeMux 是否已注册某 pattern。 // ServeMux 无公开查询 API;Handler 面走一次探测请求即可判断。 // 返回 nil 表示未注册(可安全补挂),非 nil 表示已在路由表。 // // 实现说明:Go 1.22+ ServeMux 用 Handler(r) 做匹配;若精确 pattern 已注册, // Handler 返回的 p.pattern 等于查询串。此处用最朴素的方式:构造一个指向 // 目标 pattern 的请求,若 Handler 命中且非内置 404 处理器即视为已注册。 func muxPatternRegistered(mux *http.ServeMux, pattern string) http.Handler { req, err := http.NewRequest(http.MethodGet, "http://probe.invalid"+pattern, nil) if err != nil { return nil // 构造失败按未注册处理(后续 HandleFunc 会 panic 暴露问题) } h, _ := mux.Handler(req) // 内置 404(NotFoundHandler)意味着 pattern 未注册——ServeMux.Handler 对 // 完全未命中且无 "/" 兜底的请求返回 NotFoundHandler。 if h == nil { return nil } if h == http.DefaultServeMux { return nil } // 未注册时 ServeMux.Handler 返回 http.NotFoundHandler(包级单例)。 if _, ok := h.(http.Handler); ok { // 判 404:包一层探测 recoder 看状态码不可行(Handler 只在 Serve 时执行), // 改用类型特征:ServeMux 未命中返回的 handler 即 mux 自身的 notFoundHandler, // 其与 http.NotFoundHandler() 每次为不同实例——因此不能靠指针比较。 // 简化判定:ServeMux.Handler 命中已注册 pattern 时返回该 pattern 的 handler; // 未命中时返回的不是任何用户注册的 handler。此处采用行为探测:执行一次。 w := &probeRecorder{header: http.Header{}, status: 0} h.ServeHTTP(w, req) if w.status == http.StatusNotFound { return nil } } return h } // probeRecorder 探测用 ResponseWriter(不落网络)。 type probeRecorder struct { header http.Header status int } func (p *probeRecorder) Header() http.Header { return p.header } func (p *probeRecorder) Write(b []byte) (int, error) { return len(b), nil } func (p *probeRecorder) WriteHeader(code int) { p.status = code }