1. 起因
    今天在接微信小程序码生成接口的时候发现报invalid scene hint的错误,debug后发现是因为我scene参数中的html字符被转义而导致的,原始提交的参数为qrt=cp&qrk=lottery,但是api提交的参数为qrt=cp\u0026qrk=lottery如下图所示:
    debug图

  2. 分析
    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)即可

  1. 验证
    使用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"}
可见,& 符号没有被转义
  1. 总结
    golang中,在对象转成json字符串的时候,如果不希望字符串中含有的html特殊字符被转义,可以使用Encoder对象并且SetEscapeHTML(false)即可。如果没有这种需求则使用json.Marshal即可。
Logo

新一代开源开发者平台 GitCode,通过集成代码托管服务、代码仓库以及可信赖的开源组件库,让开发者可以在云端进行代码托管和开发。旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐