【问题标题】:gin/golang gin-gonic does not parse time.Time properly for unix json?gin/golang gin-gonic 不解析时间。unix json 的正确时间?
【发布时间】:2020-09-05 17:48:12
【问题描述】:

我找不到使用 UNIX 正确执行此代码的方法:

package main

import (
  "time"
  "github.com/gin-gonic/gin"
  "net/http"
)

type Things struct {
  Name string `json:"name"`
  OneDay time.Time `json:"oneDay"`
}

type Example struct {
  Things []Things `json:"things"`
  Something int `json:"something"`
}

func TestGinGo(c *gin.Context) {
  var example Example
  c.BindJSON(&example)
  c.JSON(http.StatusOK, gin.H{"data": example})
}

func main() {
  r := gin.Default()

  r.POST("/", TestGinGo)

  r.Run("0.0.0.0:8080")
}

我这样称呼这个端点:

curl --location --request POST 'localhost:8080' \
--header 'Content-Type: application/json' \
--data-raw '{
    "things": [{
        "name": "bling",
        "oneDay": "2020-01-01T00:00:00Z"
    }],
    "something": 2
}'

回答正确:

{
    "data": {
        "things": [
            {
                "name": "bling",
                "oneDay": "2020-01-01T00:00:00Z"
            }
        ],
        "something": 2
    }
}

现在我稍微改变一下代码以像这样在 UNIX 上工作:

package main

import (
  "time"
  "github.com/gin-gonic/gin"
  "net/http"
)

type Things struct {
  Name string `json:"name"`
  OneDay time.Time `json:"oneDay" time_format:"unix"`
}

type Example struct {
  Things []Things `json:"things"`
  Something int `json:"something"`
}

func TestGinGo(c *gin.Context) {
  var example Example
  c.BindJSON(&example)
  c.JSON(http.StatusOK, gin.H{"data": example})
}

func main() {
  r := gin.Default()

  r.POST("/", TestGinGo)

  r.Run("0.0.0.0:8080")
}

我这样称呼它:

curl --location --request POST 'localhost:8080' \
--header 'Content-Type: application/json' \
--data-raw '{
    "things": [{
        "name": "bling",
        "oneDay": 1589898758007
    }],
    "something": 2
}'

我现在得到这个错误(400 bad format):

{"data":{"things":[{"name":"bling","oneDay":"0001-01-01T00:00:00Z"}],"something":0}}

我进入图书馆...我看到那里的代码可以使用“unix”:

https://github.com/gin-gonic/gin/blob/master/binding/form_mapping.go#L272

我真的很想使用 unix,因为许多语言不需要使用 unix 的库,而且我不想强制消费者使用特定格式...而且我不知道在哪里我在这里错过了球......

【问题讨论】:

  • @mkopriva 如您所见,输入使用默认格式 RFC3339...我只是在使用这些值作为输出进行生态...但是当我输入未正确解码时说格式 unix,我提供了一个数字......但是这个人做得很好:github.com/gin-gonic/gin/issues/2009 我不明白如何或为什么
  • github.com/gin-gonic/gin/issues/2009#issuecomment-519159298 说他们用那个特定的版本修复了它,你用的是什么版本的杜松子酒?
  • go 版本 go1.14.2 darwin/amd64
  • not go 版本,gin 版本,你的 gin 版本是多少
  • 查看源代码这似乎是form 仅输入功能,不支持 json。您需要改用自定义时间类型。

标签: date datetime go go-gin


【解决方案1】:
  1. time_format标签只用于form绑定,不是json;
  2. 您可以使用自定义 Marshal 和 Unmarshal 函数(请参阅 https://pkg.go.dev/encoding/json#example-package-CustomMarshalJSON
package main

import (
    "encoding/json"
    "github.com/gin-gonic/gin"
    "log"
    "net/http"
    "time"
)

type myTime time.Time

func (mt *myTime) UnmarshalJSON(bs []byte) error {
    var timestamp int64
    err := json.Unmarshal(bs, &timestamp)
    if err != nil {
        return err
    }

    *mt = myTime(time.Unix(timestamp/1000, timestamp%1000*1e6))
    return nil
}

func (mt myTime) MarshalJSON() ([]byte, error) {
    timestamp := time.Time(mt).UnixNano() / 1e6
    log.Println(time.Time(mt).UnixNano())
    return json.Marshal(timestamp)
}

type Timestamp struct {
    OneDay     myTime    `json:"oneDay" form:"oneDay"`
    AnotherDay time.Time `json:"anotherDay" form:"anotherDay" time_format:"unix"`
}

func parseTime(c *gin.Context) {
    var example Timestamp
    if err := c.Bind(&example); err != nil {
        log.Printf("bind timestamp error: %s", err)
    }
    c.JSON(http.StatusOK, gin.H{"data": example})
}

func main() {
    r := gin.Default()

    r.POST("/time", parseTime)

    r.Run("0.0.0.0:8080")
}
  1. 以 json 格式发送
curl --location --request POST 'localhost:8080/time' \
--header 'Content-Type: application/json' \
--data '{
  "oneDay": 1589898758007,
  "anotherDay": "1589898758"
}'

oneDay 是对的,anotherDay 不行

{"data":{"oneDay":1589898758007,"anotherDay":"0001-01-01T00:00:00Z"}}
  1. 以表格形式发送
curl --location --request POST 'localhost:8080/time' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'oneDay=1589898758007&anotherDay=1589898758'

两个都是对的

{"data":{"oneDay":1589898758007,"anotherDay":"2020-05-19T22:32:38+08:00"}}

【讨论】:

  • 为什么json或form的请求格式会影响响应的结果?有什么想法吗?
  • 因为Bind检查了请求的Content-Type。看这里github.com/gin-gonic/gin/blob/…
猜你喜欢
  • 1970-01-01
  • 2015-08-22
  • 2018-11-07
  • 2015-09-04
  • 1970-01-01
  • 1970-01-01
  • 2017-07-01
  • 1970-01-01
  • 2021-06-13
相关资源
最近更新 更多