python2.7 json.loads() 将字符串默认解码为

2019-05-16  本文已影响0人  zbharper

python2.7 中 str 与 unicode 的转换一直是个头疼的问题,在使用json模块进行序列化与反序列化时再次踩坑。

1)客户端产生一个字典格式的数据结构,其中带有一段utf-8编码的字符串

import json

raw = u"我爱中国".encode("utf-8")
send_data = {
    "id": 111,     #不重要
    "content": raw   # 数据内容为utf-8编码
}

print type(send_data['content'])    # str

2)客户端将数据进行json序列化,通过消息队列发送至服务器

send_body = json.dumps(send_data)
# send to rabbitmq

3)服务器端收到后进行解码,交给后端处理

# receive_body get from rabbitmq
receive_data = json.loads(receive_body)

4)后端使用数据,此时数据已经是unicode 而不是utf-8,再次解码会出错!

print type(receive.data['content'])   # unicode

从协议分层的角度,(1)与(4)处于同一逻辑层,抛开(2),(3)的json序列化与反序列化过程,发送与接收的数据格式应该相同,但是receive_data 与 send_data中的字符编码不一样,稍不注意使用(如按数据格式协议解码)就会出错。

查看json官方文档,发现在反序列化json.loads()的过程中会自动将所有字符串解码为unicode格式。而序列化过程json.dumps()会默认将非ascii编码的字符转换为unicode,同时可以通过参数ensure_ascii=False选择保持原有编码不变。有点绕,但是坑爹的地方就在于此,做几个实验:

1. 默认参数不变,对两种编码( utf8, unicode)进行序列化
>>> unicode_str = u"abc我爱中国def"     # u'abc\u6211\u7231\u4e2d\u56fddef'
>>> utf8_str = unicode_str.encode('utf-8')   # 'abc\xe6\x88\x91\xe7\x88\xb1\xe4\xb8\xad\xe5\x9b\xbddef'

>>> ser1 = json.dumps(unicode_str)
>>> ser2 = json.dumps(utf8_str)
>>> ser1
'"abc\\u6211\\u7231\\u4e2d\\u56fddef"'
>>> ser2
'"abc\\u6211\\u7231\\u4e2d\\u56fddef"' 

输入不同,序列化之后的结果相同!

2. 使用json.dumps(obj, ensure_ascii=False), 对两种编码进行序列化
>>> ser3 = json.dumps(unicode_str, ensure_ascii=False)
>>> ser4 = json.dumps(utf8_str, ensure_ascii=False)
>>> ser3
u'"abc\u6211\u7231\u4e2d\u56fddef"'
>>> ser4
'"abc\xe6\x88\x91\xe7\x88\xb1\xe4\xb8\xad\xe5\x9b\xbddef"'

序列化后的结果不同!分别保持了原有的编码!

3. 对上述的序列化字符串进行反序列化
>>> new1 = json.loads(ser1)
>>> new2 = json.loads(ser2)
>>> new3 = json.loads(ser3)
>>> new4 = json.loads(ser4)
>>> new1
u'abc\u6211\u7231\u4e2d\u56fddef'
>>> new2
u'abc\u6211\u7231\u4e2d\u56fddef'
>>> new3
u'abc\u6211\u7231\u4e2d\u56fddef'
>>> new4
u'abc\u6211\u7231\u4e2d\u56fddef'

四个序列化字符串反序列化结果全都相同!

结论

  1. 反序列化后总会得到unicode字符串,无论序列化阶段如何搞
  2. 序列化阶段通过参数设置,可能生成不同的序列化结果
  3. 要想少出错,在上层的数据协议里最好将字符串都定义为unicode格式
  4. 尽快转到python3
上一篇 下一篇

猜你喜欢

热点阅读