一次 Go json 序列化踩坑经历

848 阅读2分钟

问题

json.Marshal() 函数在处理html标签字符中,会存在转义问题。Marshal方法默认把html标签中的'<', '>' , '&'字符转义成unicode,为强制为有效UTF-8的JSON字符串,用Unicode替换符号替换无效字节。

所以当时在网上找了 这篇文章:golang——json的html转义问题

虽然他提供了解决方案 解决了字符串转义的问题,但是却带来了新的问题

type Message struct {
	Content string	
}

func main() {
	content := `content`
	m := Message{content}
        res1, _ := json.Marshal(&m)
	res2, _ := JsonMarshalNoSetEscapeHTML(&m)

	fmt.Println(len([]byte(res1)), len(res2))
        fmt.Println(string(res1) == string(res2))
}

func JsonMarshalNoSetEscapeHTML(data interface{}) ([]byte, error) {
	bf := bytes.NewBuffer([]byte{})
	jsonEncoder := json.NewEncoder(bf)
	jsonEncoder.SetEscapeHTML(false)
	if err := jsonEncoder.Encode(data); err != nil {
		return nil, err
	}

	return bf.Bytes(), nil
}

输出

21 22
false

我们期望对于普通字符串,序列化出来的字节数相同 以及 字符串比较是相等的,但是实际上并没有

原因

由于字符串不长,我们可以直接把字节数组打印出来

[123 34 67 111 110 116 101 110 116 34 58 34 99 111 110 116 101 110 116 34 125]
[123 34 67 111 110 116 101 110 116 34 58 34 99 111 110 116 101 110 116 34 125 10]

我们可以看到是 res2 比 res1 多了一个 10 。通过查看 ascii 码表,可以发现 10 表示的是 LF 也就是换行

我们再看 Encode 函数的源码

// Terminate each value with a newline.
// This makes the output look a little nicer
// when debugging, and some kind of space
// is required if the encoded value was a number,
// so that the reader knows there aren't more
// digits coming.
e.WriteByte('\n')

翻译一下:“用一个换行来结束每个值。这使得在调试时输出看起来更漂亮,如果编码的值是一个数字,则需要一些空格,这样读者就知道不会有更多的数字出现。”

总结

有时候需要对序列化出来的字符串校验md5值,如果多了一个空格 则 md5 校验会不通过。这是一个坑。至于如何解决,最简单的办法就是,返回的时候去掉多加的换行。或者在需要操作的时候再去掉

b := bf.Bytes()
return b[:len(b)-1], nil