Closed feiyangbeyond closed 5 months ago
I don't think this issue is about gin, but you can refer to the source code of Time.time and write a custom type of JSON serialization and deserialization method.
// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in the RFC 3339 format with sub-second precision.
// If the timestamp cannot be represented as valid RFC 3339
// (e.g., the year is out of range), then an error is reported.
func (t Time) MarshalJSON() ([]byte, error) {
b := make([]byte, 0, len(RFC3339Nano)+len(`""`))
b = append(b, '"')
b, err := t.appendStrictRFC3339(b)
b = append(b, '"')
if err != nil {
return nil, errors.New("Time.MarshalJSON: " + err.Error())
}
return b, nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time must be a quoted string in the RFC 3339 format.
func (t *Time) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
return nil
}
// TODO(https://go.dev/issue/47353): Properly unescape a JSON string.
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
return errors.New("Time.UnmarshalJSON: input is not a JSON string")
}
data = data[len(`"`) : len(data)-len(`"`)]
var err error
*t, err = parseStrictRFC3339(data)
return err
}
@RedCrazyGhost
I'm not sure if it's a gin error. Let me tell you the results of the investigation.
The program has thrown an error before it reaches the custom time type I wrote.
This error only occurs when making a get request and using gin to bind query. The error is invalid character '-' after top-level value
My struct:
type Foo struct {
Bar string `form:"bar"`
Time MyTime `form:"time"` // use MyTime
}
When I send get request like /foo?bar=some&time=2024-04-17 13:21:45 , gin uses json.Unmarshal to convert 2024-04-17 13:21:45
to MyTime
,
Since 2024-04-17 13:21:45
is not a normal json string, using json.Unmarshal will definitely report an error.
I think the error root cause is binding single parameter value as json when binding parameters on get request.
I can add "" before and after the time field when sending a get request, this way you can avoid this error.
I meet the same problem: my custom time type:
type CTime time.Time
func (t CTime) MarshalJSON() ([]byte, error) {
return marshalJSON[CTime](t)
}
func (t *CTime) UnmarshalJSON(b []byte) error {
s := strings.Trim(string(b), `"`)
if s == "" {
return nil
}
if len(s) <= 10 {
s = fmt.Sprintf("%s 00:00:00", s)
}
ti, err := parse(Layout, s)
if err != nil {
return err
}
*t = CTime(ti)
return nil
}
this problem append in the source code: bind query.go and the method func mapForm()
in this function about custom time type error handle
this is not ptr
maybe like gorm handle custom type?
This problem is very annoying.
Later, I used unix timestamp instead of time.Time in http request and response.
I have a new type
MyTime
, and it has implementsencoding/json.Unmarshaler
.And my struct define:
When I use http get query , the same error occurred. And after changing
MyReq.Time
type totime.Time
, it works.I hope it works with
MyTime
.Did I use it improperly?
Originally posted by @feiyangbeyond in https://github.com/gin-gonic/gin/issues/3895#issuecomment-2033774740
--
Why I use
MyTime
?I wish to control the type of time in json serialization/formatting, I use
MyTime
in get/post request to keep it consistent