package utils import ( "bytes" "encoding/json" "fmt" "io" "strings" "github.com/beego/beego/v2/server/web" ) const jsonBodyCacheKey = "__request_json_body_map" func parseRequestJSONBody(c *web.Controller) (map[string]interface{}, error) { if cached := c.Ctx.Input.GetData(jsonBodyCacheKey); cached != nil { if m, ok := cached.(map[string]interface{}); ok { return m, nil } } contentType := strings.ToLower(c.Ctx.Input.Header("Content-Type")) body := c.Ctx.Input.RequestBody if len(body) == 0 { if c.Ctx.Request != nil && c.Ctx.Request.Body != nil { readBody, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { return nil, err } body = readBody c.Ctx.Input.RequestBody = readBody c.Ctx.Request.Body = io.NopCloser(bytes.NewBuffer(readBody)) } } if len(body) == 0 { return nil, nil } trimBody := strings.TrimSpace(string(body)) if trimBody == "" { return nil, nil } if !strings.HasPrefix(trimBody, "{") && !strings.HasPrefix(trimBody, "[") { return nil, nil } var m map[string]interface{} if err := json.Unmarshal(body, &m); err != nil { if strings.Contains(contentType, "application/json") { return nil, err } return nil, nil } c.Ctx.Input.SetData(jsonBodyCacheKey, m) return m, nil } // GetRequestString gets parameter by key. // It tries form/query first, then falls back to JSON body for application/json. func GetRequestString(c *web.Controller, key string) (string, error) { v := strings.TrimSpace(c.GetString(key)) if v != "" { return v, nil } m, err := parseRequestJSONBody(c) if err != nil { return "", err } if m == nil { return "", nil } raw, ok := m[key] if !ok || raw == nil { return "", nil } switch vv := raw.(type) { case string: return strings.TrimSpace(vv), nil default: return strings.TrimSpace(fmt.Sprint(vv)), nil } }