0c9f256dfc
对应体检报告 #10-#24,一次性完成 v1.1.0 全部 13 项: - #10 storage/cache/redis/jwt/logger 五组件 Manager 化(XxxManager + DefaultXxx + SetDefaultXxxManager,包级 facade 保留兼容) - #11 删除 wire 包 + 清理 StartServerWithPort/GracefulShutdown 双轨 - #12 Lifecycle Hooks(OnInit/OnStart/OnReady/OnStop) - #13 Server 参数配置化(timeout/TLS/unix_socket/response_mode) - #14 JWTConfig.Expire 改 time.Duration + 删 AppConfig.TokenExpire - #15 response Mode 开关(ModeBusiness/ModeREST) - #16 Config.Validate 启动期校验 - #17 livez/readyz 探针路由 - #18 Prometheus metrics 中间件 + /metrics - #19 请求级 Timeout 中间件 - #21 主库探活 + replica 健康剔除 - #22 App.Go + in-flight goroutine 管理 - #24 RequestID 默认装入 + #23 核对 Breaking:删 wire、删 TokenExpire、JWTConfig.Expire 类型变更、删双轨函数。 详见 CHANGELOG 升级说明。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
117 lines
3.0 KiB
Go
117 lines
3.0 KiB
Go
package response
|
||
|
||
import (
|
||
"net/http"
|
||
|
||
"github.com/EthanCodeCraft/xlgo-core/utils"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// Response 统一响应结构
|
||
type Response struct {
|
||
Code int `json:"code"`
|
||
Msg string `json:"msg"`
|
||
Data any `json:"data,omitempty"`
|
||
RequestID string `json:"request_id,omitempty"` // 请求追踪ID
|
||
}
|
||
|
||
// PageData 分页数据结构
|
||
type PageData struct {
|
||
Items any `json:"items"`
|
||
Total int64 `json:"total"`
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
}
|
||
|
||
// getRequestID 从上下文获取请求ID
|
||
func getRequestID(c *gin.Context) string {
|
||
return c.GetString("request_id")
|
||
}
|
||
|
||
// Success 成功响应
|
||
func Success(c *gin.Context, data any) {
|
||
c.JSON(http.StatusOK, Response{
|
||
Code: CodeSuccess,
|
||
Msg: "操作成功",
|
||
Data: data,
|
||
RequestID: getRequestID(c),
|
||
})
|
||
}
|
||
|
||
// SuccessWithMsg 成功响应(自定义消息)
|
||
func SuccessWithMsg(c *gin.Context, msg string, data any) {
|
||
c.JSON(http.StatusOK, Response{
|
||
Code: CodeSuccess,
|
||
Msg: msg,
|
||
Data: data,
|
||
RequestID: getRequestID(c),
|
||
})
|
||
}
|
||
|
||
// Fail 失败响应
|
||
func Fail(c *gin.Context, msg string) {
|
||
writeResp(c, CodeFail, msg, nil)
|
||
}
|
||
|
||
// FailWithCode 失败响应(自定义错误码)
|
||
func FailWithCode(c *gin.Context, code int, msg string) {
|
||
writeResp(c, code, msg, nil)
|
||
}
|
||
|
||
// Unauthorized 未授权响应
|
||
func Unauthorized(c *gin.Context, msg string) {
|
||
writeResp(c, CodeUnauthorized, msg, nil)
|
||
}
|
||
|
||
// NotFound 资源不存在响应
|
||
func NotFound(c *gin.Context, msg string) {
|
||
writeResp(c, CodeNotFound, msg, nil)
|
||
}
|
||
|
||
// ServerError 服务器错误响应
|
||
func ServerError(c *gin.Context, msg string) {
|
||
writeResp(c, CodeServerError, msg, nil)
|
||
}
|
||
|
||
// RateLimit 请求过于频繁响应
|
||
func RateLimit(c *gin.Context) {
|
||
writeResp(c, CodeRateLimit, "请求过于频繁,请稍后再试", nil)
|
||
}
|
||
|
||
// Page 分页响应
|
||
func Page(c *gin.Context, items any, total int64, page, pageSize int) {
|
||
Success(c, PageData{
|
||
Items: items,
|
||
Total: total,
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
})
|
||
}
|
||
|
||
// Download 文件下载响应
|
||
func Download(c *gin.Context, filename string, data []byte) {
|
||
c.Header("Content-Type", "application/octet-stream")
|
||
c.Header("Content-Disposition", "attachment; filename="+filename)
|
||
c.Header("Content-Length", utils.ToString(len(data)))
|
||
c.Data(http.StatusOK, "application/octet-stream", data)
|
||
}
|
||
|
||
// DownloadWithContentType 文件下载(自定义Content-Type)
|
||
func DownloadWithContentType(c *gin.Context, filename string, contentType string, data []byte) {
|
||
c.Header("Content-Type", contentType)
|
||
c.Header("Content-Disposition", "attachment; filename="+filename)
|
||
c.Header("Content-Length", utils.ToString(len(data)))
|
||
c.Data(http.StatusOK, contentType, data)
|
||
}
|
||
|
||
// HTML HTML内容响应
|
||
func HTML(c *gin.Context, data string) {
|
||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||
c.String(http.StatusOK, data)
|
||
}
|
||
|
||
// Redirect 页面跳转
|
||
func Redirect(c *gin.Context, code int, url string) {
|
||
c.Redirect(code, url)
|
||
}
|