文章

json解析库

json库

  1. JSON 编码: 将 Go 的数据结构转换为 JSON 格式的字符串。通过 json.Marshal 函数实现。
  2. JSON 解码: 将 JSON 格式的字符串转换为 Go 的数据结构。通过 json.Unmarshal 函数实现。

相关的包:

1
2
3
import {
	"encoding/json"
}

语法

1
2
json.Marshal(待解析map/struct数据)
json.Unmarshal(待解析json数据, &结果)

基础使用(推荐做法:始终使用标签)

一、序列化结构体(struct->json)

使用 json.Marshal 将数据序列化为字节数组。适用于结构体、Map。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Person struct {
	Name string
	Age int
	Sex int
}

func main() {
	person := Person{Name: "xiaoyu", Age: 18, Sex: 1}
	b, err := json.Marshal(person) // 将结构体序列号为json字节数组
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println(string(b)) // 将json字节数组转化为字符串
}

打印出:

1
{"Name":"xiaoyu","Age":18,"Sex":1}

注意:如果结构体中的字段为小写字母开头,将不能被序列化,因为这相当于是一个局部私有属性

如果想要输出的结果为小写字母开头的key,可以为结构体添加Tag:

1
2
3
4
5
type Person struct {
	Name string   `json:"name"`
	Age  int    `json:"age"`
	Sex  int    `json:"sex"`
}

这样的话,就可以输出:

1
{"name":"xiaoyu","age":18,"sex":1}

二、序列化Map(map->json)

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
    person := make(map[string]interface{}) // value为interface{}表示值可以是多种类型
    person["name"] = "xiaoyu"
    person["age"] = 18
    person["sex"] = 1

    b, err := json.Marshal(person) // 将Map序列号为json字节数组
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Println(string(b)) // 将json字节数组转化为字符串
}

打印出:

1
{"age":18,"name":"xiaoyu","sex":1}

三、反序列化为结构体(json->struct)

方式1

使用 json.Unmarshal 将字节数组反序列化。

使用条件: 确定你的 JSON 数据不包含大数字或你可以接受默认的 float64 处理方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func main() {
	personStr := `{"name":"xiaoyu","age":18,"sex":1}`
	person := new(Person)
	err := json.Unmarshal([]byte(personStr), &person) // 将json字符串转化为byte数组,再填充到person
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println(person)
	fmt.Println(person.Name)
}

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
	Sex  int    `json:"sex"`
}

打印出:

1
2
&{xiaoyu 18 1}
xiaoyu
方式2

使用 json.DecoderUseNumber

使用条件: 如果数据中包含大数字或需要更高精度的整数,建议使用 json.DecoderUseNumber()

  • strings.NewReader 更适合直接从字符串读取数据,使用更方便。
  • bytes.NewReader 适合处理字节切片,提供更大的灵活性。
  • 两者在功能上基本相同,主要区别在于输入数据的处理方式。

解决:

  • 如果反序列化不指定结构体类型或者变量类型,则JSON中的数字类型,默认被反序列化成float64类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
)

type Person struct {
    ID   json.Number `json:"id"`
    Name string      `json:"name"`
}

func main() {
    personStr := `{"id": 1234567890123456789, "name": "Alice"}`
    var person Person

    // 使用
    decoder := json.NewDecoder(bytes.NewReader([]byte(personStr)))
    decoder.UseNumber()
    err := decoder.Decode(&person)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    fmt.Printf("ID: %v, Name: %s\n", person.ID, person.Name)
}

四、反序列化为Map(json->map)

1
2
3
4
5
6
7
8
9
10
11
func main() {
    personStr := `{"name":"xiaoyu","age":18,"sex":1}`
    person := make(map[string]interface{})
    err := json.Unmarshal([]byte(personStr), &person) // 将json字符串转化为byte数组,再填充到person
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Println(person)
    fmt.Println(person["name"])
}

打印出:

1
2
map[age:18 name:xiaoyu sex:1]
xiaoyu

Marshal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func TestJsonMarshalLength() {
	tests := []interface{}{
		nil,
		struct{}{},
		[]interface{}{},
		map[string]interface{}{},
		"",
		0,
		false,
	}

	for _, v := range tests {
		data, _ := json.Marshal(v)  // 100%完全不需要检查 len(data) == 0
		fmt.Printf("%T: len=%d, data=%s\n", v, len(data), data)
	}
}
1
2
3
4
5
6
7
<nil>: len=4, data=null
struct {}: len=2, data={}
[]interface {}: len=2, data=[]
map[string]interface {}: len=2, data={}
string: len=2, data=""
int: len=1, data=0
bool: len=5, data=false

Unmarshal 结构体字段赋予默认值 :crossed_swords:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
type Goods struct {
	ShopID     string    `json:"shop_id"`  // 零值 ""
	OuterID    int       `json:"outer_id"` // 零值 0
	UpdateTime time.Time `json:"update_time"`
	// 数组
	DescPics []string `json:"desc_pics"` // 零值 []
	AllProps []Prop   `json:"all_props"` // 零值 []
	// 指针
	CreateTime *time.Time `json:"create_time"` // 指针,零值=nil
	GoodsHot   *int       `json:"goods_hot"`   // 指针,零值=nil
	PropsPtr   *[]Prop    `json:"props_ptr"`   // 指针,零值=nil
	// 嵌套, 也遵循零值规则
	Props []Prop `json:"props"`
}

type Prop struct {
	Source   int      `json:"source"`
	PropName string   `json:"prop_name"`
	Value    []string `json:"value"`
}

func main() {
	fullJSON := `{
		"update_time":"2025-11-10T17:05:28.919345+08:00",
		"goods_hot":1,
        "props": [
          {
            "source": 2,
            "value": [
              "IPad Pro(10.5寸)"
            ]
          }
        ],
		"presale_end_time":{"type":0,"value":"0001-01-01T00:00:00Z","description":""}
	}`
	var g Goods
	_ = json.Unmarshal([]byte(fullJSON), &g)
	fmt.Printf("\n完整输入后:%+v\n", g2)
}


结果

1
完整输入后:{ShopID: OuterID:0 UpdateTime:2025-11-10 17:05:28.919345 +0800 CST DescPics:[] AllProps:[] CreateTime:<nil> GoodsHot:0xc00009e038 PropsPtr:<nil> Props:[{Source:2 PropName: Value:[IPad Pro(10.5寸)]}]}

常用序列化/反序列化操作

指定字段名

1
2
3
4
5
6
7
8
9
10
11
12
13
// tag 是结构体的元信息,可以在运行的时候通过反射的机制读取出来
// 在 tag 中添加字段名,json 序列化/反序列化时会使用该字段名
type Person struct {
    Name   string `json:"name"`   // 指定 json 序列化/反序列化时使用小写 name
    Age    int64  `json:"age"`  // 指定 json 序列化/反序列化时使用小写 age
    Height float64
}

p := Person{
    Name:   "Alice",
    Age:    18,
    Height: 160.7,
}
1
{"name":"Alice","age":18,"Height":160.7}

忽略某个字段

1
2
3
4
5
6
7
8
9
10
11
12
// 在 tag 中添加 "-",json 序列化/反序列化时会忽略该字段
type Person struct {
    Name   string  `json:"name"` // 指定 json 序列化/反序列化时使用小写 name
    Age    int64   `json:"age"` // 指定 json 序列化/反序列化时使用小写 age
    Height float64 `json:"-"`    // 指定 json 序列化/反序列化时忽略此字段
}

p1 := Person{
    Name:   "Alice",
    Age:    18,
    Height: 160.7,
}
1
2
// Height 字段被忽略
{"name":"Alice","age":18}

忽略空值字段

omitempty 只管 Marshal(编码成 JSON),不管 Unmarshal(解码到 Go)。

  • Marshal时: 字段如果是零值,且带了 omitempty,整条 key 都不会写出去,省空间。
  • Unmarshal时:不会受 omitempty 影响

⭐️ 未忽略空值字段

1
2
3
4
5
6
7
8
9
type User struct {
    Name  string   `json:"name"`
    Email string   `json:"email"`
    Hobby []string `json:"hobby"`
}

u1 := User{
    Name: "Alice",
}
1
2
// 空值字段不会被忽略
{"name":"Alice","email":"","hobby":null}

✏️ 忽略空值字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 在 tag 中添加 omitempty 会忽略空值
// 空值指的是 false、0、""、nil 指针、nil 接口、长度为 0 的数组、切片、映射
type User struct {
    Name  string   `json:"name"`
    Email string   `json:"email,omitempty"`  // json 序列化时空值时忽略此字段, 反序列化不受影响
    Hobby []string `json:"hobby,omitempty"`
}

u1 := User{
    Name: "Alice",
}

type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email,omitempty"`
	Hobby []string `json:"hobby,omitempty"`
}

func main() {
	u1 := User{Name: "Alice"}

	b, _ := json.Marshal(u1) 
	fmt.Println(string(b)) // 输出:{"name":"Alice"} // 添加 omitempty 后,空值字段会被忽略
}

指定匿名结构体字段

📚 嵌套结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type User struct {
    Name  string   `json:"name"`
    Email string   `json:"email,omitempty"`
    Hobby []string `json:"hobby,omitempty"`
    Profile //不会有profile字段 // 默认忽略
}

type Profile struct {
    Website string `json:"site"`
    Slogan  string `json:"slogan"`
}

u1 := User{
    Name:  "Alice",
    Hobby: []string{"足球", "篮球"},
}
1
2
// 匿名嵌套 Profile 时,序列化后的 json 串为单层的
{"name":"Alice","hobby":["足球","篮球"],"site":"","slogan":""}

✌ 如果想要变成嵌套的json串,需要改为具名嵌套或定义字段tag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type User struct {
    Name    string   `json:"name"`
    Email   string   `json:"email,omitempty"`
    Hobby   []string `json:"hobby,omitempty"`
    Profile `json:"profile"` //会有profile字段
}

type Profile struct {
    Website string `json:"site"`
    Slogan  string `json:"slogan"`
}

u1 := User{
    Name:  "Alice",
    Hobby: []string{"足球", "篮球"},
}
1
2
// 定义字段 tag 后,序列化后的 json 串为双层的
{"name":"Alice","hobby":["足球","篮球"],"profile":{"site":"","slogan":""}}

✍ 如果想要忽略嵌套结构体空值字段,仅添加omitempty是不够的,需要使用嵌套的结构体指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type User struct {
    Name     string   `json:"name"`
    Email    string   `json:"email,omitempty"`
    Hobby    []string `json:"hobby,omitempty"`
    *Profile `json:"profile,omitempty"`
}

type Profile struct {
    Website string `json:"site"`
    Slogan  string `json:"slogan"`
}

u1 := User{
    Name:  "七米",
    Hobby: []string{"足球", "篮球"},
}
1
{"name":"七米","hobby":["足球","篮球"]}

不修改原结构体忽略空值字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 如果不需要将 User 结构体的 Password 字段序列化,但是又不想修改 User 结构体,
// 可以创建另外一个结构体匿名嵌套原 User,同时指定 Password 字段为匿名结构体指针类型,并添加 omitempty 标签
package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Name     string `json:"name"`
    Password string `json:"password"`
}

type NewUser struct {
    *User              // 匿名嵌套
    Password *struct{} `json:"password,omitempty"` //json 序列化时空值时忽略此字段, 反序列化不受影响
}

func main() {
    u := User{
        Name:     "Alice",
        Password: "123456",
    }
    b, err := json.Marshal(NewUser{User: &u})
    if err != nil {
        fmt.Printf("json.Marshal u1 failed, err:%v\n", err)
        return
    }
    fmt.Printf("%s\n", b) // {"name":"Alice"}
}

使用匿名结构体添加字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 如果想扩展结构体字段,但有时候又没有必要单独定义新的结构体,可以使用匿名结构体简化操作
package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Name     string `json:"name"`
    Password string `json:"password"`
}

func main() {
    u := User{
        Name:     "Alice",
        Password: "123456",
    }
    // 使用匿名结构体内嵌 User 并添加额外字段Token
    b, err := json.Marshal(struct {
        *User        
        Token string `json:"token"`
    }{
        User:  &u,
        Token: "91je3a4s72d1da96h",
    })
    if err != nil {
        fmt.Printf("json.Marshal u1 failed, err:%v\n", err)
        return
    }
    fmt.Printf("%s\n", b) // {"name":"Alice","password":"123456","token":"91je3a4s72d1da96h"}
}

使用匿名结构体组合多个结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 同理,可以使用匿名结构体来组合多个结构体来序列化与反序列化数据
package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Name     string `json:"name"`
    Password string `json:"password"`
}

type Post struct {
    ID    int    `json:"id"`
    Title string `json:"title"`
}

func main() {
    u := User{
        Name:     "Alice",
        Password: "123456",
    }

    p := Post{
        ID:    123456,
        Title: "hello world",
    }

    b, err := json.Marshal(struct {
        *User
        *Post
    }{
        User: &u,
        Post: &p,
    })
    if err != nil {
        fmt.Printf("json.Marshal u1 failed, err:%v\n", err)
        return
    }
    fmt.Printf("%s\n", b) // {"name":"Alice","password":"123456","id":123456,"title":"hello world"}

    jsonStr := `{"name":"Alice","password":"123456","id":123456,"title":"Hello World"}`
    var (
        u2 User
        p2 Post
    )
    if err := json.Unmarshal([]byte(jsonStr), &struct {
        *User
        *Post
    }{&u2, &p2}); err != nil {
        fmt.Printf("json.Unmarshal failed, err:%v\n", err)
        return
    }
    fmt.Printf("%#v\n", u2) // main.User{Name:"Alice", Password:"123456"}
    fmt.Printf("%#v\n", p2) // main.Post{ID:123456, Title:"Hello World"}
}

处理字符串格式数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 如果 json 串使用的是字符串格式的数字,可以在 tag 中添加 string 来告诉 json 包反序列化时从字符串解析相应字段
package main

import (
    "encoding/json"
    "fmt"
)

type Card struct {
    ID    int64   `json:"id,string"`  // 添加 string tag
    Score float64 `json:"score,string"`  // 添加 string tag
}

func main() {
    // json 串中使用的是字符串格式的数字,不添加 string tag 反序列会报错
    jsonStr := `{"id": "1234567","score": "88.50"}`
    var c1 Card
    if err := json.Unmarshal([]byte(jsonStr), &c1); err != nil {
        fmt.Printf("json.Unmarsha jsonStr1 failed, err:%v\n", err)
        return
    }
    fmt.Printf("%#v\n", c1) // main.Card{ID:1234567, Score:88.5}
}

整数变为浮点数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// JSON 协议中没有整型和浮点型的区别,它们统称为 number
// 如果将 JSON 格式的数据反序列化为 map[string]interface{} 时,数字都变成科学计数法表示的浮点数
package main

import (
    "encoding/json"
    "fmt"
)

type student struct {
    ID   int64  `json:"id"`
    Name string `json:"q1mi"`
}

func main() {
    s := student{
        ID:   123456789,
        Name: "Alice",
    }
    b, _ := json.Marshal(s)

    var m map[string]interface{}
    _ = json.Unmarshal(b, &m)
    fmt.Printf("%#v\n", m["id"]) // 1.23456789e+08
    fmt.Printf("%T\n", m["id"])  // float64
}

如果想更合理的处理数字,需要使用decoder去反序列化,使用json.Number类型,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
)

type student struct {
    ID   int64  `json:"id"`
    Name string `json:"q1mi"`
}

func main() {
    s := student{
        ID:   123456789,
        Name: "Alice",
    }
    b, _ := json.Marshal(s)

    // 使用功能 decoder 方式进行反序列,指定使用 number 类型
    var m map[string]interface{}
    decoder := json.NewDecoder(bytes.NewReader(b))
    decoder.UseNumber()
    _ = decoder.Decode(&m)

    // 反序列后,类型为 json.Number 类型
    fmt.Printf("%#v\n", m["id"]) // "123456789"
    fmt.Printf("%T\n", m["id"])  // json.Number

    // 根据字段的实际类型调用 Float64() 或 Int64() 函数获取对应类型
    id, _ := m["id"].(json.Number).Int64()
    fmt.Printf("%#v\n", id) // 123456789
    fmt.Printf("%T\n", id)  // int64
}

json.Number类型的源码定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// A Number represents a JSON number literal.
type Number string

// String returns the literal text of the number.
func (n Number) String() string { return string(n) }

// Float64 returns the number as a float64.
func (n Number) Float64() (float64, error) {
    return strconv.ParseFloat(string(n), 64)
}

// Int64 returns the number as an int64.
func (n Number) Int64() (int64, error) {
    return strconv.ParseInt(string(n), 10, 64)
}

处理不确定层级的 json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 如果 json 串没有固定格式导致不好定义与其相对应的结构体时,可以使用 json.RawMessage 将原始字节数据保存下来
package main

import (
    "encoding/json"
    "fmt"
)

type sendMsg struct {
    User string `json:"user"`
    Msg  string `json:"msg"`
}

func main() {
    jsonStr := `{"sendMsg":{"user":"Alice","msg":"永远不要高估自己"},"say":"Hello"}`
    var data map[string]json.RawMessage
    if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
        fmt.Printf("json.Unmarshal jsonStr failed, err:%v\n", err)
        return
    }

    var msg sendMsg
    if err := json.Unmarshal(data["sendMsg"], &msg); err != nil {
        fmt.Printf("json.Unmarshal failed, err:%v\n", err)
        return
    }
    fmt.Printf("%#v\n", msg) // main.sendMsg{User:"Alice", Msg:"永远不要高估自己"}
}

自定义序列化/反序列化

1
2
3
4
5
6
7
8
9
10
// 可以通过实现 json.Marshaler/json.Unmarshaler 接口来实现自定义的事件格式解析
// 解决方法: 实现Marshaler
type Marshaler interface {
    MarshalJSON() ([]byte, error)
}

// 解决方法: 实现Unmarshaler
type Unmarshaler interface {
    UnmarshalJSON([]byte) error
}

例子1

问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 内置的 json 包不识别常用的字符串时间格式,如 2022-05-24 14:50:00
package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type Post struct {
    ID         int       `json:"id"`
    Title      string    `json:"title"`
    CreateTime time.Time `json:"create_time"` //
}

func main() {
    // 序列化
    p := Post{
        ID:         123456,
        Title:      "hello world",
        CreateTime: time.Now(),
    }
    b, err := json.Marshal(p)
    if err != nil {
        fmt.Printf("json.Marshal p1 failed, err:%v\n", err)
        return
    }
    fmt.Printf("%s\n", b) // {"id":123456,"title":"hello world","create_time":"2022-05-24T14:58:45.3702937+08:00"}

    
    // 反序列化
    jsonStr := `{"id":123456,"title":"hello world","create_time":"2022-05-24 14:50:00"}`
    var p2 Post
    if err := json.Unmarshal([]byte(jsonStr), &p2); err != nil {
        fmt.Printf("json.Unmarshal failed, err:%v\n", err)
        return
    }
    fmt.Printf("%#v\n", p2) //报错: json.Unmarshal failed, err:parsing time "\"2022-05-24 14:50:00\"" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse " 14:50:00\"" as "T"
}

解决方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 通过实现 json.Marshaler/json.Unmarshaler 接口来自定义时间字段的事件格式解析
package main

import (
    "encoding/json"
    "fmt"
    "time"
)

const layout = "2006-01-02 15:04:05"

type Post struct {
    ID         int       `json:"id"`
    Title      string    `json:"title"`
    CreateTime time.Time `json:"create_time"`
}

// MarshalJSON 为 Post 类型自定义序列化方法
func (p Post) MarshalJSON() ([]byte, error) {
    type TempPost Post // 定义与 Post 字段一致的新类型
    return json.Marshal(struct {
        *TempPost         // 直接嵌套 Post 会进入死循环,需要使用新类型 TempPost
        CreateTime string `json:"create_time"`
    }{
        TempPost:   (*TempPost)(&p),
        CreateTime: p.CreateTime.Format(layout),
    })
}

// UnmarshalJSON 为 Post 类型自定义反序列化方法
func (p *Post) UnmarshalJSON(data []byte) error {
    type TempPost Post // 定义与 Post 字段一致的新类型
    tp := struct {
        *TempPost        // 直接嵌套 Post 会进入死循环,需要使用新类型 TempPost
        CreateTime string `json:"create_time"`
    }{
        TempPost: (*TempPost)(p),
    }

    if err := json.Unmarshal(data, &tp); err != nil {
        return err
    }

    var err error
    p.CreateTime, err = time.Parse(layout, tp.CreateTime)
    if err != nil {
        return err
    }
    return nil
}

func main() {
    // 序列化
    p := Post{
        ID:         123456,
        Title:      "hello world",
        CreateTime: time.Now(),
    }
    b, err := json.Marshal(p)
    if err != nil {
        fmt.Printf("json.Marshal p1 failed, err:%v\n", err)
        return
    }
    fmt.Printf("%s\n", b) // {"id":123456,"title":"hello world","create_time":"2022-05-24 18:30:03"}

    // 反序列化
    jsonStr := `{"id":123456,"title":"hello world","create_time":"2022-05-24 14:50:00"}`
    var p2 Post
    if err := json.Unmarshal([]byte(jsonStr), &p2); err != nil {
        fmt.Printf("json.Unmarshal failed, err:%v\n", err)
        return
    }
    fmt.Printf("%#v\n", p2) // main.Post{ID:123456, Title:"hello world", CreateTime:time.Date(2022, time.May, 24, 14, 50, 0, 0, time.UTC)}
}

例子2

问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
type DWEventReq struct {
	DEvent []DEvent `json:"-"` // 不直接序列化
}

type DEvent struct {
	MsgType    string `json:"msgType"`    // 消息类型
	PlatShopId string `json:"platShopId"` // 商家店铺Id
	Paypload   string `json:"paypload"`   // 消息内容
	Ts         int64  `json:"ts"`         // 消息时间戳
}

// 自定义反序列化方法,支持直接数组或包装对象
func (d *DWEventReq) UnmarshalJSON(data []byte) error {
	// 尝试作为数组直接反序列化
	var events []DEvent
	if err := json.Unmarshal(data, &events); err == nil {
		d.DEvent = events
		return nil
	}
	return nil
}

func DWEvent(ctx context.Context, req *proto.DWEventReq, rsp *proto.DWEventRsp) error {
	if req == nil || len(req.DEvent) == 0 {
		logger.Errorf(ctx, "DwEvent request is empty or has no events")
		return nil
	}

	reqBytes, err := json.Marshal(req.DEvent)
	if err != nil {
		logger.WithError(err).Errorf(ctx, "failed to marshal DEvent array")
		return err
	}

	if len(reqBytes) == 0 {
		logger.Errorf(ctx, "DwEvent reqBytes is empty")
		return nil
	}

	logger.Debugf(ctx, "DwEvent reqBytes=[%s]", reqBytes)

	// input msg to channel, async to handle
	worker.Input(ctx, reqBytes)

	return nil
}

使用

1
2
3
4
5
6
7
8
9
curl --location 'http://localhost:8095/message/event' \
--header 'Content-Type: application/json' \
--data '[
    {
        "msgType": "PRODUCT_ON_SALE",
        "platShopId": "MH2zDrm1b1f2Sena",
        ...
    }
]'

原因:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type DWEventReq struct {
  DEvent []DEvent  // 不能填json 标签
}

// 填了就变成下面这样传参了
{
    "DEvent": [
    {
        "msgType": "order",
        "platShopId": "123",
        "paypload": "data",
        "ts": 123456
    }
    ]
}

参考

Return Top

© 2024- lfj