个人认为,JSON是目前针对程序员而言可读性(readability)最佳的数据传输格式之一,并且JSON完整地考虑到了数据传输中的转义,避免出现各种注入风险。当对JSON进行序列化操作时(Go中称为marshal),根据JSON标准的说明,需要对字符串中的以下字符进行转义:
符号
名称
转义后的字符串
"
双引号
\"
/
斜杠
\/
\
反斜杠
\\
\b
退格符
\f
垂直制表符
Tab
水平制表符
\t
\r
回车
\n
换行符
<
左尖括号
\u003C
>
右尖括号
\u003E
&
And符号
\u0026
另外针对Go语言,个人建议再转义一个百分号%为\u0025,原因是在Go的各种字符串格式化操作中,百分号是一个关键字符,这样可以避免在打日志或者其他设计格式化的操作时出现错误。
这里所说的Unicode字符,准确而言指的是在ASCII范围之外的字符,也就是值大于0x7F的Unicode字符。
其实大部分情况下,UTF-8已经成为现代编程语言约定俗成的标准了,因此在JSON序列化时,只要简单地对Unicode字符的值转为二进制然后按照网络字节序打包就可以了。
但是在某些情况下,当对端采用的不是UTF-8,或者是对端采用的不是网络字节序时(比如对方是技术底下/落后、但却话语权强大的客户/合作商/集成商),这个时候,大家统一采用ASCII编码,就能够避免这些问题了。
那么JSON是怎么使用ASCII编码来传输Unicode的呢?从前文的转义其实就可以一窥端倪了——JSON采用的是\uXXXX的形式来表示一个Unicode字符的。每个Unicode字符表示法中,XXXX必须是4个十六进制数,即便高位为0也需要补全。通过这种方式,编码和传输Unicode字符。在ASCII为主的数据传输中,这种编码方式比较稳妥,并且不会额外增加过多的数据量。当然对于Unicode字符比较多的情况下(比如大量的中文),这就需要程序员考虑一下额外带来的网络花销了。
读者可能会注意到了,\uXXXX格式最大只能支持到0xFFFF,但Unicode早就已经超过了这个范围。大于65535的字符要怎么表示呢?首先,绝对不是简单地采用\uXXXXX,这会导致编码错误。
比如我们用u代表这样的一个字符,UTF-16的处理方法如下:
举例说明:代表地球的颜文字符号“”,其编码值为0x1F30D,按照UTF-16编码过程为: