解决Go json.Marshal() 将HTML字符串转义的问题

解决Go json.Marshal() 将HTML字符串转义的问题

# 阅读本文,你将了解
# 1. json.Marshal()实现
# 2. HTML字符串被转义的解决方案

0. 前言

最近在做项目的时候遇到一个问题,做MQTT设备鉴权是,有一个token算法,而这个token算法将会输出一个嵌套有&/的HTML字符串。我在采用fmt.Println()打印输出,发现上述特殊字符并没有被转义,但当我通过json.Marshal() json序列化输出到文件中时,发现特殊字符被转义了,便有了本文。本文仅记录该问题定位和解决思路。

1. 问题发现

在将设备 device struct结构体进行token算法计算之后,通过json序列化写入文件中时,发现部分字符串被转义了。

type Devices struct {
	Id        int    `json:"id"`
	ApiKey    string `json:"apiKey"`
	AuthToken string `json:"auth_token"`
}
func main() {

	var outDevices []Devices
	// todo 封装device 相关的token信息
	log.Println("outDevices:",outDevices)
	bytes, err := json.Marshal(outDevices)
	if err != nil {
		log.Fatalf("json marshal is fail %+v", err)
	}
	WriteFile(bytes) //输出到文件中
}
未被序列化的输出--> outDevices: [{10022143 OTlmZWUyN2E0NTY5ZTZhNGE3YjQ= version=2020-12-16&res=products%2F102425%2Fdevices%2F10022143&et=1908125107&method=sha1&sign=O6Ba%2FG%2BTj0JPq3o9i5A8vw4iPIA%3D}]

通过查看输出的文件内容,发现&被转义为了\u0026,如下图:
问题分析01

2. 问题分析

  • 1.怀疑json.Marshal() 序列化,将&被转义了;
  • 2.ioutil.WriteFile()将json序列化之后的[]byte转义了。

打印输出json.Marshal() 之后的[]byte 数组,发现&被转义为了\u0026.

json.Marshal: [{"id":10022143,"apiKey":"OTlmZWUyN2E0NTY5ZTZhNGE3YjQ=","auth_token":"version=2020-12-16\u0026res=products%2F102425%2Fdevices%2F10022143\u0026et=1908125107\u0026method=sha1\u0026sign=O6Ba%2FG%2BTj0JPq3o9i5A8vw4iPIA%3D"}]
//结合上文,这里可以看见 `&` 被转义成了 `\u0026`

查看 json.Marshal()源码,在注解上找到了线索。

在这里插入图片描述

google翻译一下:

字符串值编码为强制转换为有效UTF-8的JSON字符串,用Unicode替换符文替换无效字节。
这样就可以安全地将JSON嵌入HTML <script>标记中,并使用HTMLEscape对字符串进行编码,
HTMLEscape会将“ <”,““>”,“&”,U + 2028和U + 2029
替换为“ \” u003c”,“ \ u003e”,“ \ u0026”,“ \ u2028”和“ \ u2029”。 
使用编码器时可以禁用此替换,通过调用SetEscapeHTML(false)。

在看json.Marshal()源码,发现escapeHTML:true,由此可见json.Marshal()默认会将字符串值编码为强制转换为有效UTF-8的JSON字符串,用Unicode替换符文替换无效字节。

golang 源码

3. 问题解决

问题已经很清楚了,就是被json.Marshal()方法将字符串转义了。接下来就是怎么想法不被字符串转义了。

注意最后一句:

// This replacement can be disabled when using an Encoder,
// by calling SetEscapeHTML(false)

这里已经说了解决方案了: 使用 Encoder 生成字符串,并调用SetEscapeHTML(false)

type Devices struct {
	Id        int    `json:"id"`
	ApiKey    string `json:"apiKey"`
	AuthToken string `json:"auth_token"`
}
func main() {
	var outDevices []Devices
	// todo 封装device 相关的token信息
	log.Println("outDevices:",outDevices)
    // 解决问题 
	byteBuf := bytes.NewBuffer([]byte{})
	encoder := json.NewEncoder(byteBuf)
	encoder.SetEscapeHTML(false) // 不转义 特殊字符
	err := encoder.Encode(outDevices)
	if err != nil {
		panic(err)
	}
	log.Println("json.Marshal:",byteBuf)
	WriteFile(byteBuf.Bytes()) //输出到文件中
}
未被序列化的输出--> outDevices: [{10022143 OTlmZWUyN2E0NTY5ZTZhNGE3YjQ= version=2020-12-16&res=products%2F102425%2Fdevices%2F10022143&et=1908126970&method=sha1&sign=1%2BlnRyK%2FItthV%2FwI%2Fuj%2Bkt%2FhPf8%3D}]
Encoder 编码-->  Encoder: [{"id":10022143,"apiKey":"OTlmZWUyN2E0NTY5ZTZhNGE3YjQ=","auth_token":"version=2020-1216&res=products%2F102425%2Fdevices%2F10022143&et=1908126970&method=sha1&sign=1%2BlnRyK%2FItthV%2FwI%2Fuj%2Bkt%2FhPf8%3D"}]
// 发现改问题得到了解决。

4.总结

  • 遇到问题,先定位,找到问题的根源
  • 要培养自己追查源码的能力,读懂了源码,基本上能解决一半以上的问题
  • 合理利用搜索引擎,英语很重要
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值