// Package httpx 提供管理接口共用的 HTTP 辅助(JSON 信封、客户端 IP、HTTPS 判定)。 package httpx import ( "encoding/json" "errors" "io" "net/http" ) // ErrorBody 是失败响应里的 error 对象。 type ErrorBody struct { Code string `json:"code"` Message string `json:"message"` } // Envelope 是管理接口通用响应信封。 type Envelope struct { OK bool `json:"ok"` Data any `json:"data,omitempty"` Error *ErrorBody `json:"error,omitempty"` } // WriteJSON 写入 JSON 响应。 func WriteJSON(w http.ResponseWriter, status int, v any) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(status) enc := json.NewEncoder(w) enc.SetEscapeHTML(false) _ = enc.Encode(v) } // WriteOK 写入成功信封。 func WriteOK(w http.ResponseWriter, data any) { WriteJSON(w, http.StatusOK, Envelope{OK: true, Data: data}) } // WriteError 写入失败信封。 func WriteError(w http.ResponseWriter, status int, code, message string) { WriteJSON(w, status, Envelope{ OK: false, Error: &ErrorBody{ Code: code, Message: message, }, }) } // DecodeJSON 解码请求 JSON 体;空体对 dst 保持零值。 func DecodeJSON(r *http.Request, dst any) error { defer func() { _ = r.Body.Close() }() dec := json.NewDecoder(r.Body) dec.DisallowUnknownFields() if err := dec.Decode(dst); err != nil { if errors.Is(err, io.EOF) { return nil } return err } return nil }