關於form表單或者Ajax向后台發送數據時,數據格式的探究


最近在做一個資產管理系統項目,其中有一個部分是客戶端向服務端發送采集到的數據的,服務端是Django寫的,客戶端需要用requests模塊模擬發送請求

假設發送的數據是這樣的:

  data = {'status' : True , 'content' : { 'k1' : 'xxxx' , 'k2' : 'xxxx' }}

是字典套字典的,然后通過requests.post(url = url ,data = data) 發送,會發現在服務端接收到的數據是這樣的,<QueryDict>:{  [ 'status' , 'content' ] }

發生了什么,為什么只取到了key,但是沒有取到values呢,既然能取到key,說明Django是沒問題的

那問題肯定就出在requests.post發送數據上了

好了,鋪墊完畢

想一下,ajax是怎么發送數據的

$.ajax ({

  url : 'xxxx',

  data : {

    k1 : 1,
    k2 : 'abc',
    k3 : [1,2,3,4,'s']

    }

  })

吶,只能發送這三種格式吧,沒有字典吧,如果非要發送字典,可以通過JSON把字典轉成字符串格式,JSON.stringfy({ 'k1':'xxx' })

form 表單也是這樣的,而requests.post就是仿造的form表單提交

發現了問題,我們再來剖析一下http發送post請求的過程

ajax發送的data是個字典,是鍵值對的形式,在http的post請求過程中,把這種鍵值對轉換成

k1=xxx&k2=xxx這種格式,並且會帶上一個請求頭:

  content-type : application/x-www-form-urlencoded

這個請求頭和k1=xxx&k2=xxx這種格式是以一一對應的,只要發送這個格式,就必須帶上這個請求頭,后台的request.POST會根據這個請求頭解析這種格式,還原成以前字典的格式。而且這種格式和這個請求頭都是默認的,所以如果我們不修改,直接發送文章開始說的那種格式,服務端就不能解析,所以只拿到字典的key,沒拿到value

  但如果是現在這種情況,我們發送的不是這個格式,而是想要發送JSON.stringfy({ 'k1':'xxx' })這種json字符串,也是有辦法的,ajax可以自定義請求頭,改成這樣:  

$.ajax ({

  url : 'xxxx',

  headers : { 'content-type' : 'application/json' },

  data : JSON.stringfy( {k1 : 1,k2 : 'abc',k3 : [1,2,3,4,'s']})

  })

這樣后台就會根據json去解析接收到的數據(json格式的字符串)

但是不能用request.POST了,因為request.POST 默認是按k1=xxx&k2=xxx這種格式解析數據的,

應該用request.body去拿數據,再用json.loads一下就拿到這個字典了

 

默認情況下,form 表單,ajax 以及 requests.post 都是這樣處理的

所以在這個項目中,我們需要用requests自定義這個請求頭,這個寫法就很簡單了

requests.post(url = url ,json = data) ,就行了,把原來的data關鍵字參數換成json關鍵字參數。

內部做的就是,1.序列化data,2.帶一個請求頭'content-type' : 'application/json'

這樣,服務端拿到的數據,先decode解碼一下,在json.loads,就是我們熟悉的字典了

 

 

在ajax中,像后台發送數據:

GET請求:

  1.如果是字符串,數字,可以正常發送:

    $.ajax({

      url : 'xxxx',

      type : 'get',

      data : { 'k1':'v1','k2':'v2' }

      ....

      })

  2.如果是字典(數組)格式

  a.發送的格式為:'test_list':[1,2,3,'abc']

    后台request.GET 拿到的數據是這樣的:    

'test_list[]': ['1', '2', '3', 'abc']

  b.ajax發送時添加一個traditional:true

    后台request.GET 拿到的數據是這樣的:

'test_list': ['1', '2', '3', 'abc']

 POST請求:

發送的數據格式: 

var test_list = [1,2,'abc'];
var test_dict = {'kk1':'vv1','kk2':'vv2'}
    data: {'k1':123,'k2':'abc','k3':test_list,'k4':test_dict}

后台依次打印

print(request.POST)
print(json.loads(request.body.decode('utf-8')))
print(request.body)

 

1.就直接這樣發送:

后台拿到的數據:

<QueryDict: {'k1': ['123'], 'k2': ['abc'], 'k3[]': ['1', '2', 'abc'], 'k4[kk1]': ['vv1'], 'k4[kk2]': ['vv2']}>
報錯
b'k1=123&k2=abc&k3%5B%5D=1&k3%5B%5D=2&k3%5B%5D=abc&k4%5Bkk1%5D=vv1&k4%5Bkk2%5D=vv2'

2.加上traditional:true

<QueryDict: {'k1': ['123'], 'k2': ['abc'], 'k3': ['1', '2', 'abc'], 'k4': ['[object Object]']}>
報錯
b'k1=123&k2=abc&k3=1&k3=2&k3=abc&k4=%5Bobject+Object%5D'

3.ajax通過JSON.stringify( ) 發送

前端:

data: JSON.stringify({'k1':123,'k2':'abc','k3':test_list,'k4':test_dict})

后台拿到的數據:

<QueryDict: {'{"k1":123,"k2":"abc","k3":[1,2,"abc"],"k4":{"kk1":"vv1","kk2":"vv2"}}': ['']}>
{'k1': 123, 'k2': 'abc', 'k3': [1, 2, 'abc'], 'k4': {'kk1': 'vv1', 'kk2': 'vv2'}}
b'{"k1":123,"k2":"abc","k3":[1,2,"abc"],"k4":{"kk1":"vv1","kk2":"vv2"}}'

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM