-
起因
今天在接微信小程序码生成接口的时候发现报invalid scene hint
的错误,debug后发现是因为我scene参数中的html字符被转义而导致的,原始提交的参数为qrt=cp&qrk=lottery
,但是api提交的参数为qrt=cp\u0026qrk=lottery
如下图所示:
-
分析
debug后发现,是因为经过了json.Marshal方法后,html的字符才被转义的。
查看json.Marshal源码
func Marshal(v interface{}) ([]byte, error) {
e := newEncodeState()
err := e.marshal(v, encOpts{escapeHTML: true})
if err != nil {
return nil, err
}
buf := append([]byte(nil), e.Bytes()...)
e.Reset()
encodeStatePool.Put(e)
return buf, nil
}
源码中就看到了其中的“猫腻”—>>escapeHTML:true
,再看看方法的注释说明,以下是其中一段说明
// String values encode as JSON strings coerced to valid UTF-8,
// replacing invalid bytes with the Unicode replacement rune.
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
// to keep some browsers from misinterpreting JSON output as HTML.
// Ampersand "&" is also escaped to "\u0026" for the same reason.
// This escaping can be disabled using an Encoder that had SetEscapeHTML(false)
// called on it.
简单的说就是,字符串在编码为JSON字符串时会被强制转换为有效的UTF-8,为了防止一些浏览器在JSON输出误解以为是HTML,“<”,“>”,“&”这类字符会被进行转义,如果不想被转义,就使用Encoder,并且SetEscapeHTML(false)即可。
- 验证
使用json.Marshal生成json字符串
func main() {
testMap := map[string]string{
"demo": `https://xxx.xxx.com?a=1&b=2`,
}
bytes, err := json.Marshal(testMap)
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
}
输出结果:{"demo":"https://xxx.xxx.com?a=1\u0026b=2"}
可见,& 符号已经被转义
使用Encoder生成字符串
func main() {
testMap := map[string]string{
"demo": `https://xxx.xxx.com?a=1&b=2`,
}
byteBuf := bytes.NewBuffer([]byte{})
encoder := json.NewEncoder(byteBuf)
encoder.SetEscapeHTML(false)
err := encoder.Encode(testMap)
if err != nil {
panic(err)
}
fmt.Println(byteBuf.String())
}
输出结果:{"demo":"https://xxx.xxx.com?a=1&b=2"}
可见,& 符号没有被转义
- 总结
golang中,在对象转成json字符串的时候,如果不希望字符串中含有的html特殊字符被转义,可以使用Encoder对象并且SetEscapeHTML(false)即可。如果没有这种需求则使用json.Marshal即可。