Files
rill/internal/httpx/httpx.go
T
kevin b683fb293e 增加注册登录与鉴权,并按功能拆分 internal 模块
- 新增 /api/auth/register、/api/auth/login,JWT 签发与 Bearer 鉴权中间件
- notes 需登录,users/user-groups 仅管理员;auth 配置项随版本 1→2 自动补全
- internal/api 仅保留路由装配,拆分为 auth/user/usergroup/note/httpx/testutil
- 同步更新 Swagger 文档与前端注册接口路径
2026-09-20 02:03:06 +08:00

81 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package httpx 提供 HTTP 接口的公共辅助:统一错误响应、分页参数与路径参数解析。
package httpx
import (
"errors"
"log/slog"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
const (
defaultPageSize = 20
maxPageSize = 100
)
// ErrorResponse 统一错误响应。
type ErrorResponse struct {
Error string `json:"error" example:"记录不存在"`
}
// ParsePagination 解析 page/page_size,非法值回落默认。
func ParsePagination(c *gin.Context) (int, int) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", strconv.Itoa(defaultPageSize)))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > maxPageSize {
pageSize = defaultPageSize
}
return page, pageSize
}
// ParseID 解析路径参数 id0 或非法值返回 false 并写入 400。
func ParseID(c *gin.Context) (uint, bool) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
c.JSON(http.StatusBadRequest, ErrorResponse{Error: "id 无效"})
return 0, false
}
return uint(id), true
}
// RespondDBError 记录数据库错误并返回 500。
func RespondDBError(c *gin.Context, err error) {
slog.ErrorContext(c.Request.Context(), "数据库操作失败", "err", err, "path", c.Request.URL.Path)
c.JSON(http.StatusInternalServerError, ErrorResponse{Error: "服务器内部错误"})
}
// RespondServerError 记录业务错误并返回 500。
func RespondServerError(c *gin.Context, err error, msg string) {
slog.ErrorContext(c.Request.Context(), msg, "err", err, "path", c.Request.URL.Path)
c.JSON(http.StatusInternalServerError, ErrorResponse{Error: "服务器内部错误"})
}
// RespondGetError 查询类错误:记录不存在返回 404,其余按数据库错误处理。
func RespondGetError(c *gin.Context, err error) {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, ErrorResponse{Error: "记录不存在"})
return
}
RespondDBError(c, err)
}
// RespondDuplicateOrDBError 写入类错误:唯一约束冲突返回 409,其余按数据库错误处理。
func RespondDuplicateOrDBError(c *gin.Context, err error, duplicateMsg string) {
if errors.Is(err, gorm.ErrDuplicatedKey) {
c.JSON(http.StatusConflict, ErrorResponse{Error: duplicateMsg})
return
}
RespondDBError(c, err)
}
// RespondUnauthorized 中止请求并返回 401。
func RespondUnauthorized(c *gin.Context) {
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrorResponse{Error: "未登录或登录已过期"})
}