关于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"}}'
原文地址:https://www.cnblogs.com/zhang-can/p/7631262.html