contentType
当我们使用form表单提交数据时,有一个enctype属性,默认情况下不写
此时我们提交数据时,会默认将数据以application/x-www-form-urlencoded的编码方式发送
该形式的数据为"k1=v1&k2=v2"格式,可以看成是一组组的键值对
但是当我们要发送图片等二进制文件时,上面的形式就无法实现了,此时我们会将enctype属性设置为form-data
这时我们就既可以发送键值对的数据,又可以发送较大的二进制文件了
同样,在使用ajax发送数据时,默认情况下,我们发送的get和post请求都是以application/x-www-form-urlencoded的编码方式发送的
但是我现在想要向后端发送一个json字符串形式的数据,该怎么办呢
这里我们就需要使用ajax里的contentType参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<button class="json_send">send</button>
{% csrf_token %}
<script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
<script>
$(".json_send").click(function () {
$.ajax({
url:"/ajax_send/",
data:JSON.stringify({"k1":"v1"}),
type:"post",
contentType:"application/json",
success:function (data) {
console.log(data)
}
});
</script>
如果以上面的形式直接发送,我们会发现后端接收时,request.POST和request.GET内都取不到值
def ajax_send(request):
import json
print(request.GET) # <QueryDict: {}>
print(request.POST) # <QueryDict: {}>
print(request.body.decode()) # {"k1":"v1"}return HttpResponse("OK")
这就要从帮助Django处理http请求的wsgiref模块说起了
该模块主要做了三件事:
1.封装了一个socket对象,通过该对象与客户端建立连接
2.按照http协议解析数据
3.按照http协议封装响应数据
当该模块解析数据时,会有一定的规则
wsgi:
if content_type: url_encoded:
request.body :post(get)数据-------> request.POST(GET)
当数据格式为application/x-www-form-urlencoded时,他会把数据写到request.POST或者request.GET中,如果为其它格式,则不会,此时我们如果想拿到数据必须从request.body中取
这样我们就完成了json字符串格式的数据发送,但是我们注意到这里我们发送的是post请求,但是却未带csrftoken的相关数据,如果通过中间件的话,这个请求会被拒绝,那我们该如何将csrftoken的值一起发送过去呢
这里我们先研究一下csrftoken的中间件是如何取相应的值的
CsrfViewMiddleware:
if random_str=request.POST.get("csrfmiddlewaretoken")
if random_str=="347289asd328":
pass
elif request.META.get("X-CSRFToken"):
request.META.get("X-CSRFToken")=="asdasdh23470ahsd37sa"
else:
return Htttpresponse("forbidden error")
我们发现中间件会先从request.POST中取,但是我们的数据不会被放到request.POST中,所以取不到
这时中间件又会从请求头部的X-CSRFToken中取值,如果还取不到,那么会forbidden
所以我们此时就要想办法将csrftoken的值放到请求头的X-CSRFToken中
其实每当我们发送一次请求时,我们会发现在我们的COOKIE中也会带有csrftoken的相关内容,此时就从中取值放入X-CSRFToken中
<script src="{% static ‘js/jquery.cookie.js‘ %}"></script> // 必须要引用,不然无法使用$.cookie方法
$.ajax({
headers:{"X-CSRFToken":$.cookie(‘csrftoken‘)},
})
我们的代码为
$(".json_send").click(function () {
$.ajax({
url:"/ajax_send/",
data:JSON.stringify({"k1":"v1"}),
type:"post",
headers:{"X-CSRFToken":$()},
contentType:"application/json",
success:function (data) {
console.log(data)
}
});
dataType
该属性表示我们期待服务器发送回来的数据是一个什么类型
如:dataType:json,表示我们期待服务器端发送的是一个json格式的数据
这个属性并不会改变服务器端的内容,但是当客户端拿到服务器端的数据后,ajax方法会将数据进行parser操作,得到我们想要的类型
error和complete
$(".send_Ajax").click(function(){
$.ajax({
url:"/handle_Ajax/",
type:"POST",
data:{username:"Yuan",password:123},
success:function(data){
alert(data)
},
//=================== error============
error: function (jqXHR, textStatus, err) {
// jqXHR: jQuery增强的xhr
// textStatus: 请求完成状态
// err: 底层通过throw抛出的异常对象,值与错误类型有关
console.log(arguments);
},
//=================== complete============
complete: function (jqXHR, textStatus) {
// jqXHR: jQuery增强的xhr
// textStatus: 请求完成状态 success | error
console.log(‘statusCode: %d, statusText: %s‘, jqXHR.status, jqXHR.statusText);
console.log(‘textStatus: %s‘, textStatus);
},
我们使用success回调函数是在执行不出错时执行的,如果执行过程中出了错误,则会执行error的回调函数,而complete是不管出不出错都会执行的
