json序列化的转义
当对 JSON 进行序列化操作时(Go 中称为 marshal),根据 JSON 标准的说明,需要对字符串中的以下字符进行转义:
产生的坑
在做卡片消息的时候,需要支持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)}
}