diff --git a/sdks/storage/object.go b/sdks/storage/object.go index 827558b..fd82606 100644 --- a/sdks/storage/object.go +++ b/sdks/storage/object.go @@ -100,8 +100,8 @@ const ObjectDownloadPath = "/object/download" type ObjectDownload struct { UserID UserID `form:"userID" json:"userID" binding:"required"` ObjectID ObjectID `form:"objectID" json:"objectID" binding:"required"` - Offset int64 `form:"offset" json:"offset"` - Length *int64 `form:"length" json:"length"` + Offset int64 `form:"offset" json:"offset,omitempty"` + Length *int64 `form:"length" json:"length,omitempty"` } type DownloadingObject struct { Path string diff --git a/utils/http/http.go b/utils/http/http.go index 59d5d97..d496daa 100644 --- a/utils/http/http.go +++ b/utils/http/http.go @@ -9,8 +9,10 @@ import ( "net/http" "net/textproto" ul "net/url" + "reflect" "strings" + "github.com/mitchellh/mapstructure" "gitlink.org.cn/cloudream/common/pkgs/iterator" "gitlink.org.cn/cloudream/common/utils/math2" "gitlink.org.cn/cloudream/common/utils/serder" @@ -285,13 +287,13 @@ func PostMultiPart(url string, param MultiPartRequestParam) (*http.Response, err defer muWriter.Close() if param.Form != nil { - mp, err := serder.ObjectToMap(param.Form) + mp, err := objectToStringMap(param.Form) if err != nil { return fmt.Errorf("formValues object to map failed, err: %w", err) } for k, v := range mp { - err := muWriter.WriteField(k, fmt.Sprintf("%v", v)) + err := muWriter.WriteField(k, v) if err != nil { return fmt.Errorf("write form field failed, err: %w", err) } @@ -351,17 +353,17 @@ func prepareQuery(req *http.Request, query any) error { return nil } - mp, ok := query.(map[string]any) + mp, ok := query.(map[string]string) if !ok { var err error - if mp, err = serder.ObjectToMap(query); err != nil { + if mp, err = objectToStringMap(query); err != nil { return fmt.Errorf("query object to map: %w", err) } } values := make(ul.Values) for k, v := range mp { - values.Add(k, fmt.Sprintf("%v", v)) + values.Add(k, v) } req.URL.RawQuery = values.Encode() @@ -373,17 +375,17 @@ func prepareHeader(req *http.Request, header any) error { return nil } - mp, ok := header.(map[string]any) + mp, ok := header.(map[string]string) if !ok { var err error - if mp, err = serder.ObjectToMap(header); err != nil { + if mp, err = objectToStringMap(header); err != nil { return fmt.Errorf("header object to map: %w", err) } } req.Header = make(http.Header) for k, v := range mp { - req.Header.Set(k, fmt.Sprintf("%v", v)) + req.Header.Set(k, v) } return nil } @@ -412,17 +414,17 @@ func prepareFormBody(req *http.Request, body any) error { return nil } - mp, ok := body.(map[string]any) + mp, ok := body.(map[string]string) if !ok { var err error - if mp, err = serder.ObjectToMap(body); err != nil { + if mp, err = objectToStringMap(body); err != nil { return fmt.Errorf("body object to map: %w", err) } } values := make(ul.Values) for k, v := range mp { - values.Add(k, fmt.Sprintf("%v", v)) + values.Add(k, v) } data := values.Encode() @@ -448,3 +450,40 @@ func setValue(values ul.Values, key, value string) ul.Values { values.Add(key, value) return values } + +func objectToStringMap(obj any) (map[string]string, error) { + anyMap := make(map[string]any) + dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + TagName: "json", + Result: &anyMap, + WeaklyTypedInput: true, + }) + if err != nil { + return nil, err + } + + err = dec.Decode(obj) + if err != nil { + return nil, err + } + + ret := make(map[string]string) + for k, v := range anyMap { + val := reflect.ValueOf(v) + for val.Kind() == reflect.Ptr { + if val.IsNil() { + break + } else { + val = val.Elem() + } + } + + if val.Kind() == reflect.Pointer { + ret[k] = "" + } else { + ret[k] = fmt.Sprintf("%v", val) + } + } + + return ret, nil +} diff --git a/utils/http/http_test.go b/utils/http/http_test.go new file mode 100644 index 0000000..2776275 --- /dev/null +++ b/utils/http/http_test.go @@ -0,0 +1,32 @@ +package http + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func Test_objectToStringMap(t *testing.T) { + Convey("包含指针", t, func() { + type A struct { + Val *int `json:"Val,omitempty"` + Nil *int `json:"Nil,omitempty"` + Omit *int `json:"Omit"` + } + + v := 10 + a := A{ + Val: &v, + Nil: nil, + Omit: nil, + } + + mp, err := objectToStringMap(a) + So(err, ShouldBeNil) + + So(mp, ShouldResemble, map[string]string{ + "Val": "10", + "Omit": "", + }) + }) +} diff --git a/utils/serder/serder.go b/utils/serder/serder.go index e8ded8c..6c7b72a 100644 --- a/utils/serder/serder.go +++ b/utils/serder/serder.go @@ -6,9 +6,9 @@ import ( "fmt" "io" "reflect" - "strings" jsoniter "github.com/json-iterator/go" + "github.com/mitchellh/mapstructure" ) var unionHandler = UnionHandler{ @@ -163,78 +163,13 @@ func MapToObject(m map[string]any, obj any, opt ...MapToObjectOption) error { } func ObjectToMap(obj any) (map[string]any, error) { - ctx := WalkValue(obj, func(ctx *WalkContext, event WalkEvent) WalkingOp { - switch e := event.(type) { - case StructBeginEvent: - mp := make(map[string]any) - ctx.StackPush(mp) - - case StructArriveFieldEvent: - if !WillWalkInto(e.Value) { - ctx.StackPush(e.Value.Interface()) - } - case StructLeaveFieldEvent: - val := ctx.StackPop() - mp := ctx.StackPeek().(map[string]any) - jsonTag := e.Info.Tag.Get("json") - if jsonTag == "-" { - break - } - - opts := strings.Split(jsonTag, ",") - keyName := opts[0] - if keyName == "" { - keyName = e.Info.Name - } - - if contains(opts, "string", 1) { - val = fmt.Sprintf("%v", val) - } - - mp[keyName] = val - - case StructEndEvent: - - case MapBeginEvent: - ctx.StackPush(make(map[string]any)) - case MapArriveEntryEvent: - if !WillWalkInto(e.Value) { - ctx.StackPush(e.Value.Interface()) - } - case MapLeaveEntryEvent: - val := ctx.StackPop() - mp := ctx.StackPeek().(map[string]any) - mp[fmt.Sprintf("%v", e.Key)] = val - case MapEndEvent: - - case ArrayBeginEvent: - ctx.StackPush(make([]any, e.Value.Len())) - case ArrayArriveElementEvent: - if !WillWalkInto(e.Value) { - ctx.StackPush(e.Value.Interface()) - } - case ArrayLeaveElementEvent: - val := ctx.StackPop() - arr := ctx.StackPeek().([]any) - arr[e.Index] = val - case ArrayEndEvent: - } - - return Next - - }, WalkOption{ - StackValues: []any{make(map[string]any)}, + mp := make(map[string]any) + dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + TagName: "json", + Result: &mp, }) - - return ctx.StackPop().(map[string]any), nil -} - -func contains(arr []string, ele string, startIndex int) bool { - for i := startIndex; i < len(arr); i++ { - if arr[i] == ele { - return true - } + if err != nil { + return nil, err } - - return false + return mp, dec.Decode(obj) }