Golang Json Marshal引起的转义问题

Json.Marshal对特殊字符转义

背景: 使用golang做网关进行转发请求时候,发现转发的java响应中的json中的url参数&被进行转义

  • 转发前原始数据: {"url":"http://abcd.com?param=1&a=2"}
  • 转发后: {"url":"http://abcd.com?param=1\u0026a=2"}

查看源码

1
2
3
4
5
6
7
8
// String values encode as JSON strings coerced to valid UTF-8,  
// replacing invalid bytes with the Unicode replacement rune.
// So that the JSON will be safe to embed inside HTML <script> tags,
// the string is encoded using HTMLEscape,
// which replaces "<", ">", "&", U+2028, and U+2029 are escaped
// to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029".
// This replacement can be disabled when using an Encoder,
// by calling SetEscapeHTML(false).

含义说:

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

测试

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"bytes"
"encoding/json"
"fmt"
)

func main() {
text := "http://abcd.com?param=1&a=2"
marshal, _ := json.Marshal(text)
fmt.Println(string(marshal))

bf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(bf)
jsonEncoder.SetEscapeHTML(false)
jsonEncoder.Encode(text)
fmt.Println(bf.String())
}

输出:

1
2
"http://abcd.com?param=1\u0026a=2"
"http://abcd.com?param=1&a=2"

解决方案

使用编码器:

1
2
3
4
bf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(bf)
jsonEncoder.SetEscapeHTML(false)
jsonEncoder.Encode(text)