python2.7 json.loads() 將字符串默認(rèn)解碼為unicode

python2.7 中 str 與 unicode 的轉(zhuǎn)換一直是個(gè)頭疼的問(wèn)題,在使用json模塊進(jìn)行序列化與反序列化時(shí)再次踩坑。

1)客戶端產(chǎn)生一個(gè)字典格式的數(shù)據(jù)結(jié)構(gòu),其中帶有一段utf-8編碼的字符串

import json

raw = u"我愛(ài)中國(guó)".encode("utf-8")
send_data = {
    "id": 111,     #不重要
    "content": raw   # 數(shù)據(jù)內(nèi)容為utf-8編碼
}

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

2)客戶端將數(shù)據(jù)進(jìn)行json序列化,通過(guò)消息隊(duì)列發(fā)送至服務(wù)器

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

3)服務(wù)器端收到后進(jìn)行解碼,交給后端處理

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

4)后端使用數(shù)據(jù),此時(shí)數(shù)據(jù)已經(jīng)是unicode 而不是utf-8,再次解碼會(huì)出錯(cuò)!

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

從協(xié)議分層的角度,(1)與(4)處于同一邏輯層,拋開(kāi)(2),(3)的json序列化與反序列化過(guò)程,發(fā)送與接收的數(shù)據(jù)格式應(yīng)該相同,但是receive_data 與 send_data中的字符編碼不一樣,稍不注意使用(如按數(shù)據(jù)格式協(xié)議解碼)就會(huì)出錯(cuò)。

查看json官方文檔,發(fā)現(xiàn)在反序列化json.loads()的過(guò)程中會(huì)自動(dòng)將所有字符串解碼為unicode格式。而序列化過(guò)程json.dumps()會(huì)默認(rèn)將非ascii編碼的字符轉(zhuǎn)換為unicode,同時(shí)可以通過(guò)參數(shù)ensure_ascii=False選擇保持原有編碼不變。有點(diǎn)繞,但是坑爹的地方就在于此,做幾個(gè)實(shí)驗(yàn):

1. 默認(rèn)參數(shù)不變,對(duì)兩種編碼( utf8, unicode)進(jìn)行序列化
>>> unicode_str = u"abc我愛(ài)中國(guó)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"' 

輸入不同,序列化之后的結(jié)果相同!

2. 使用json.dumps(obj, ensure_ascii=False), 對(duì)兩種編碼進(jìn)行序列化
>>> 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"'

序列化后的結(jié)果不同!分別保持了原有的編碼!

3. 對(duì)上述的序列化字符串進(jìn)行反序列化
>>> 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'

四個(gè)序列化字符串反序列化結(jié)果全都相同!

結(jié)論

  1. 反序列化后總會(huì)得到unicode字符串,無(wú)論序列化階段如何搞
  2. 序列化階段通過(guò)參數(shù)設(shè)置,可能生成不同的序列化結(jié)果
  3. 要想少出錯(cuò),在上層的數(shù)據(jù)協(xié)議里最好將字符串都定義為unicode格式
  4. 盡快轉(zhuǎn)到python3
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 字符是用戶可以讀寫的最小單位。計(jì)算機(jī)所能支持的字符組成的集合,就叫做字符集。字符集通常以二維表的形式存在。二維表的...
    劉惜有閱讀 8,365評(píng)論 2 14
  • 字符集和編碼簡(jiǎn)介 在編程中常??梢砸?jiàn)到各種字符集和編碼,包括ASCII,MBCS,Unicode等字符集。確切的說(shuō)...
    蘭山小亭閱讀 9,068評(píng)論 0 13
  • 說(shuō)明:本文是我在readthedocs看到的,覺(jué)得很不錯(cuò)所以轉(zhuǎn)載過(guò)來(lái),有刪改,原文地址點(diǎn)這里。 實(shí)用Unicode...
    aurora閱讀 1,049評(píng)論 0 6
  • 1 字符編碼簡(jiǎn)介 1.1 ASCII ASCII:American Standard Code for Infor...
    hufengreborn閱讀 8,526評(píng)論 3 23
  • 之前提到四月天,第一個(gè)想到的一定是林徽因,她的《你是人間的四月天》大概寫了一個(gè)像初春一樣美好的人。在詩(shī)里,四月是一...
    我喜歡怪人閱讀 937評(píng)論 0 0

友情鏈接更多精彩內(nèi)容