今天給一位同學解決post發(fā)送數據格式為json格式的請求,順便確認一下問題歸屬。
背景:
用postman工具發(fā)送一個數據格式為json的請求,得到了服務器的響應。
用python的requests庫寫的請求,卻報錯了。沒有得到該有的結果。
解決方法:
先確認自己的請求信息和函數使用正確。包括請求頭、請求體和參數傳遞。
看服務端的日志,如果服務端的日志當中收到了這2個請求的請求數據,看日志中提示什么錯誤并比對一下2份請求數據的不同,順便有需要找開開聊聊。
基于此,來說說requests中發(fā)送json格式的處理。
1、json數據格式的請求頭
在post請求當中,json數據格式的請求,請求頭常規(guī)為:Content-Type:application/json
2、requests庫中 post請求的json參數
post請求方法:post(url,data=None,json=None,**kwargs)
python的requests的post請求中,有一個json參數。源碼中對于此參數的說明如下:

一個json序列化的python對象。python中字典表達與json很相似。
在post請求中,對傳進來的json值,會做如下處理:
1、會使用json模塊中的dumps方法轉成json數據。
2、會增加消息頭中的content_type為application/json
所以,json參數不需要提前使用json模塊的方法轉成json字符串。
請注意,這里有坑:如果在傳參時,提前轉換成json字符串:requests.request("post",url,json=json.dumps(a),headers=headers)
在post請求中,還會再使用jsons模塊轉成json數據。那么此時的請求數據會在最外多了一層引號。
請求數據結果為:"{\"pwd\": \"1234567890\", \"mobilephone\": \"18611000001\"}"
而實際上我們要發(fā)送的數據是沒有外層引號的,即:{\"pwd\": \"1234567890\", \"mobilephone\": \"18611000001\"}
源碼如下:

3、示例代碼(僅為用法示例。演示接口并不支持application/json格式):
importrequestsa={"mobilephone":"18611000001","pwd":"xxxxxxxxxxxx"}url="http://XXXXXXXX"#消息頭指定headers={'Content-Type':'application/json;charset=UTF-8'}#發(fā)送post請求 json參數直接為一個字典數據。res=requests.request("post",url,json=a,headers=headers)print(res.status_code)print(res.text)
打印發(fā)送出去的請求數據,請求的結果:
sessions.py499行打印發(fā)送請求數據:請求頭為:{'User-Agent':'python-requests/2.19.1','Accept-Encoding':'gzip, deflate','Content-Type':'application/json;charset=UTF-8','Content-Length':'51','Connection':'keep-alive','Accept':'*/*'}請求體為:b'{"pwd": "1234567890", "mobilephone": "18611000001"}'
200{"status":0,"code":"20103","data":null,"msg":"手機號不能為空"}
json 請求中固定鍵名順序 & 消除鍵和值之間的空格
實際工作中遇到了以下2種情況。
服務端要求json字符串,鍵名的順序固定
服務端對于接收到的json數據中,若key和value之間有空格,則解析不了。
第1種情況:服務端要求json字符串,鍵名的順序固定
服務端在解析客戶端請求時,要求收到的請求json數據中,鍵名的順序要固定 。比如第一個鍵名必須是mac,第二個鍵名必須是agentCode等。
而我們使用requests發(fā)送請求數據時,我們是對字典進行json處理的,順序并不是固定的。
處理方法:在給requests傳參時,就給固定順序的字典就好。
使用collections.OrderedDict。它是有序字典,記住了鍵值對的添加順序。
請注意:如果初始化的時候同時傳入多個參數,它們的順序是隨機的,不會按照位置順序存儲。
示例代碼:
importcollections
content=collections.OrderedDict()content["mac"]="NDU1N2RkOTRiYjQ3ZDI5YzI0ZmI5YTQ3ZjMxZGU0OTc2YWY2ZTc3Zg=="content["agentcode"]="100001"content["msgbody"]={"customercode":"02000003","sourceinfo":[{"SourceCode":"10001","startdate":"20190601","enddate":"20190601"}]}
print(content)
#輸出結果:按鍵名添加的順序輸出OrderedDict([('mac','NDU1N2RkOTRiYjQ3ZDI5YzI0ZmI5YTQ3ZjMxZGU0OTc2YWY2ZTc3Zg=='),('agentcode','100001'),('msgbody',{'sourceinfo':[{'SourceCode':'10001','startdate':'20190601','enddate':'20190601'}],'customercode':'02000003'})])
通過使用orderedDict處理之后,將content作為requests請求中json參數值。那么發(fā)給服務器端的數據,就是固定的鍵名順序。
處理之后,服務器收到的請求數據:

第2種情況:服務端對于接收到的json數據中,若key和value之間有空格,則解析不了。
在解決了固定順序鍵名問題之后,可能你還會遇到,后臺開發(fā)大佬 跟你說:不行啊,你這鍵名和鍵值之間有空格,我們不支持解析。
這種情況下,要么你讓開發(fā)改代碼,要么你自己發(fā)送的請求中去掉空格。如果你說服不了開發(fā)改,那就只能自己處理啦。自己的處理的話,請繼續(xù)往下看。
此乃空格:

首先,找原因。空格是怎么來的??
在requests庫的源碼當中,發(fā)送出去的請求數據,默認鍵名和鍵值之間都是帶空格的。
在源碼當中,對傳進來的json參數,使用json庫的dumps函數轉換成json對象,而dumps函數默認設置了鍵名和鍵值之間的留有一個空格。



所以,要消除鍵與值之間的空格,需要在requests的源碼當中,將參數轉換成json對象時,設置separators的值去掉空格。這樣發(fā)往服務器的數據中鍵名和值之間就沒有空格了。
修改源碼如下:
在requests源碼的models.py文件中,找到prepare_body函數,修改如下圖片中,紅色框框中的內容:指定json中鍵名和鍵值之間無空格

修改完成之后,再次向服務器發(fā)送json數據格式的post請求,服務器收到的數據如下(可以看到鍵名和值之間沒有空格了哦。。):

json 請求中中文亂碼處理
最近收到一個問題:json格式請求數據中有中文,導致服務端簽名失敗。
問題詳情:
一位同學在發(fā)送json格式的post請求時,請求數據中有中文內容:
{"inputCodes":["6932608700850"],"terminal":{"status":1,"channel":"D002","storeCode":"2107","passage":"D002","storeName":"重百超市黃泥塝店","identity":"","maxProductCount":5,"posId":"D002"}}
header={"client_id":"DataSync","sign":"46BA170CFC30C571358E59EDDA63B506","Content-Type":"application/json;charset=UTF-8"}
在使用requests庫的post請求發(fā)送出去之后,服務端收到的不是中文,導致簽名失敗,數據如下:
{"terminal": {"status": 1, "channel": "D002", "identity": "", "passage": "D002", "maxProductCount": 5, "posId": "D002", "storeName": "\u91cd\u767e\u8d85\u5e02\u9ec4\u6ce5\u585d\u5e97", "storeCode": "2107"}, "inputCodes": ["6932608700850"]}

希望在服務端中收到的數據中,中文仍然是中文,因為有些服務端并沒有此做處理。
解決方法:
requests庫中,在處理json格式的請求時調用的json.dumps方法參數ensure_ascii默認為True.表示序列化時對中文默認使用的ascii編碼。
如果想要顯示中文,則將此參數的值改為False即可。
源碼修改:
在requests源碼的models.py文件中,找到prepare_body函數。找到如下圖中的代碼,在comlexjson.dumps(json)里加個參數ensure_ascii=False.

保存源碼的修改之后,再次運行,在服務器端就能看到中文啦。
如果對你有幫助的話,點個贊收個藏,給作者一個鼓勵。也方便你下次能夠快速查找。
如有不懂還要咨詢下方小卡片,博主也希望和志同道合的測試人員一起學習進步
在適當的年齡,選擇適當的崗位,盡量去發(fā)揮好自己的優(yōu)勢。
我的自動化測試開發(fā)之路,一路走來都離不每個階段的計劃,因為自己喜歡規(guī)劃和總結,文章來源:http://www.zghlxwxcb.cn/news/detail-467537.html
測試開發(fā)視頻教程、學習筆記領取傳送門!?。?/span>文章來源地址http://www.zghlxwxcb.cn/news/detail-467537.html

到了這里,關于requests 發(fā)送一個 json 格式的 post 請求的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!