json操作注意事项与技巧

268 阅读1分钟

json序列化的转义

当对 JSON 进行序列化操作时(Go 中称为 marshal),根据 JSON 标准的说明,需要对字符串中的以下字符进行转义: image.png

产生的坑

在做卡片消息的时候,需要支持markdown类型的消息,而尖括号在json序列化以后会被转义掉,导致客户端解析展示的时候出现问题。

解决办法

用自定义的json解析器,然后设置EscapeHTML为false

func jsonMarshalWithEscapeHTML(v interface{}) string {
	buf := &bytes.Buffer{}
	en := json.NewEncoder(buf)
	en.SetEscapeHTML(false)
	en.Encode(v)
	return buf.String()
}

func jsonMarshal(v interface{}) string {
	buf := &bytes.Buffer{}
	en := json.NewEncoder(buf)
	en.Encode(v)
	return buf.String()
}

func TestQuery(t *testing.T) {
	m := map[string]string{
		"name": "<wqd>",
	}
	fmt.Println("jsonMarshal:", jsonMarshal(m))
	fmt.Println("jsonMarshalWithEscapeHTML:", jsonMarshalWithEscapeHTML(m))
}

=== RUN   TestQuery
jsonMarshal: {"name":"\u003cwqd\u003e"}

jsonMarshalWithEscapeHTML: {"name":"<wqd>"}

--- PASS: TestQuery (0.00s)

复杂json结构的解析

转义json字符串的解析

{
"msg_type":"rich_text",
"msg_body":"{\"text\":\"hello word\"}"
}

直接json.unmarshal即可

func TestJson(t *testing.T) {
	type SendMsgReq struct {
		MsgType  string `json:"msg_type"`
		MsgBody string `json:"msg_body"`
	}
	in := `{
"msg_type":"rich_text",
"msg_body":"{\"text\":\"hello word\"}"
}`
	res := &SendMsgReq{}
	json.Unmarshal([]byte(in), res)
	b := map[string]string{}
	json.Unmarshal([]byte(res.MsgBody), &b) //注意,这里一定要传map的指针,否则解不出来
	fmt.Println(b)
}


=== RUN   TestJson
map[text:hello word]
--- PASS: TestJson (0.00s)
PASS

可变json对象的解析

用map[string]interface{}来解析可变的json对象,然后根据参数决定具体断言成什么类型

type SendMsgReq struct {
	MsgType string                 `json:"msg_type"`
	MsgBody map[string]interface{} `json:"msg_body"`
}

type TextMsg struct {
	Text string `json:"text"`
}

type ImageMsg struct {
	Height string `json:"height"`
	Url    string `json:"url"`
}

func TestJson(t *testing.T) {

	in := `{"msg_type":"text","msg_body":{"text":"hello word"}}`
	res := &SendMsgReq{}
	json.Unmarshal([]byte(in), &res)
	if res.MsgType == "text" {
		fmt.Println("文本的内容:", MapToTextMsg(res.MsgBody).Text)
	}

	image := `{
"msg_type":"image",
"msg_body":{"url":"http://www.baidu.com"}
}`
	resI := &SendMsgReq{}
	json.Unmarshal([]byte(image), resI)

	if resI.MsgType == "image" {
		fmt.Println("图片的链接:", MapToTextImage(resI.MsgBody).Url)
	}
}

func MapToTextMsg(in map[string]interface{}) *TextMsg {
	return &TextMsg{Text: in["text"].(string)}
}

func MapToTextImage(in map[string]interface{}) *ImageMsg {
	return &ImageMsg{Url: in["url"].(string)}
}