package httputil import ( "encoding/json" "errors" "io" "net" "net/http" "net/url" "server/internal/config" "server/internal/model/common" "server/internal/pkg/errs" "server/internal/pkg/validator" "strconv" "strings" "github.com/go-chi/chi/v5" ) // Pagination 分页请求参数 func Pagination(r *http.Request) *common.Pagination { q := r.URL.Query() // page 默认 1 page := int32(1) if p := q.Get("page"); p != "" { if v, err := strconv.Atoi(p); err == nil && v >= 1 { page = int32(v) } } // pageSize 默认 10 pageSize := int32(10) if ps := q.Get("page_size"); ps != "" { if v, err := strconv.Atoi(ps); err == nil && v >= 1 && v <= 100 { pageSize = int32(v) } } return &common.Pagination{ Page: page, PageSize: pageSize, } } func URLParamInt32(r *http.Request, key string) (int32, error) { v := chi.URLParam(r, key) if v == "" { return 0, errs.ErrIDRequired } n, err := strconv.ParseInt(v, 10, 32) if err != nil { return 0, errs.ErrInvalidID } return int32(n), nil } func BindJson(r *http.Request, dest any) error { if err := json.NewDecoder(r.Body).Decode(dest); err != nil { if errors.Is(err, io.EOF) { return errs.ErrEmptyBody } return errs.ErrInvalidJSON } if err := validator.Struct(dest); err != nil { return err } return nil } // ClientIP 获取客户端 IP,依次从 X-Forwarded-For、X-Real-IP、RemoteAddr 取值 func ClientIP(r *http.Request) string { if xff := r.Header.Get("X-Forwarded-For"); xff != "" { parts := strings.Split(xff, ",") if len(parts) > 0 { return strings.TrimSpace(parts[0]) } } if ip := r.Header.Get("X-Real-IP"); ip != "" { return ip } // RemoteAddr: IP:port host, _, err := net.SplitHostPort(r.RemoteAddr) if err == nil { return host } return r.RemoteAddr } func BuildFileUrl(path *string) string { if path == nil || *path == "" { return "" } baseURL := config.GetString("file.base_url") if baseURL == "" { return "" } result, err := url.JoinPath(baseURL, *path) if err != nil { return "" } return result }