Files
pj0235-eai_agentplatform/eai_agentplatform/backend-go/internal/web/response.go
T
eaiadmin 89ae31c998 feat: 微信公众号技能包重命名(weixin_public_account)并增强功能
- 将 wechat_official_account 重命名为 weixin_public_account,符合中文命名规范
- 新增 DOCX 文档生成技能、聊天历史、请求 ID 中间件
- 增强工作流、热点服务、文章服务等模块功能
- 前端同步重命名组件和 API
- 新增架构文档 AR13/AR14、专员文档更新
- 补充测试用例(seed_specialists_test, db_migration_test)

Co-Authored-AI: yes
2026-09-24 21:13:19 +08:00

79 lines
1.9 KiB
Go

package web
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
// CtxRequestID Gin Context 中存放 request_id 的键(由 middleware.RequestID 写入)。
const CtxRequestID = "req_id"
// RequestIDOf 从 Gin Context 读取本次请求的 request_id(无则返回空串)。
func RequestIDOf(c *gin.Context) string {
if v, ok := c.Get(CtxRequestID); ok {
if s, ok := v.(string); ok {
return s
}
}
return ""
}
// OK 成功响应信封 {"code":0,"message":"success","data":...,"error":null}
func OK(c *gin.Context, data any) {
c.JSON(http.StatusOK, gin.H{
"code": CodeOK,
"message": "success",
"data": data,
"error": nil,
})
}
// Fail 错误响应信封,统一输出四层模型:
//
// {"code": 稳定业务错误码, "message": 用户主提示, "data": null,
// "error": {"category":分类, "status":HTTP状态码, "hint":下一步建议, "request_id":追踪编号, "details":开发上下文}}
//
// 并回写 X-Request-ID 响应头,便于前后端与日志联查。
func Fail(c *gin.Context, e *AppError) {
requestID := RequestIDOf(c)
e.RequestID = requestID
c.Header("X-Request-ID", requestID)
errorObj := gin.H{
"category": e.Category,
"status": e.StatusCode,
"hint": e.Hint,
"request_id": requestID,
}
if e.Details != nil {
errorObj["details"] = e.Details
}
logFail(c, e)
c.JSON(e.StatusCode, gin.H{
"code": e.Code,
"message": e.Message,
"data": nil,
"error": errorObj,
})
}
// logFail 记录结构化错误日志,满足可定位要求:request_id / method / path / status / code / category。
func logFail(c *gin.Context, e *AppError) {
if e == nil {
return
}
req := c.Request
method := ""
path := ""
if req != nil {
method = req.Method
path = req.URL.Path
}
log.Printf("HTTP ERROR [%s] status=%d code=%d %s %s -> %s request_id=%s",
e.Category, e.StatusCode, e.Code, method, path, e.Message, e.RequestID)
}