AJAX准备的知识:JSON
JSON指的是JavaScript对象表示法,也是轻量级的文本数据交换的格式
并且独立于语言,具有自我描述性,更易理解。
注意:JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。
python与JS之间用json数据之间的转换:
合格的JSON格式的对象:
["one", "two", "three"] { "one": 1, "two": 2, "three": 3 } {"names": ["张三", "李四"] } [ { "name": "张三"}, {"name": "李四"} ]
不合格的JSON格式的对象:
{ name: "张三", 'age': 32 } ,{ "name": 张三, 'age': 32 }// 属性名和后面的值必须使用双引号 [32, 64, 128, 0xFFF] // 不能使用十六进制值 { "name": "张三", "age": undefined } // 不能使用undefined { "name": "张三", "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'), "getName": function() {return this.name;} // 不能使用函数和日期对象 }
XML和JSON都使用结构化方法来标记数据,只不过JSON 格式有两个显著的优点:1.书写简单,一目了然;
2.符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。
AJAX的介绍
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程,即局部的刷新)
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
AJAX的应用场景:
我们前端往后端发请求的方式:
1. 直接在地址栏输入URL
2. a标签
3. form表单
4. AJAX
HTTP请求的类型:
GET
POST
AJAX特点:
1. 异步
2. 局部刷新(偷偷发请求)
AJAX缺点:
请求零碎,滥用对服务端压力大
用jQuery封装的ajax方法:
$("#b1").on("click", function () { // 点击 id是b1的按钮要做的事儿 var i1 = $("#t1").val(); var i2 = $("#t2").val(); // 往后端发数据 $.ajax({ url: "/ajax_demo/", type: "get", data: {"t1": i1, "t2": i2}, success: function (arg) { {#alert(arg);#} // 把返回的结果填充到 id是i3的input框中 $("#t3").val(arg); } }) });
$.ajax的参数:
data参数中的键值对,如果值值不为字符串,需要将其转换成字符串类型。用json将数据类型转变为字符串传递给后端。
$("#b1").on("click", function () { $.ajax({ url:"/ajax_add/", type:"GET", datatype:"json" data:{"i1":$("#i1").val(),"i2":$("#i2").val(),"hehe": JSON.stringify([1, 2, 3])}, success:function (data) { $("#i3").val(data); } }) })
datatype: "josn",是帮你把数据封装为json格式的字符串,然后传递给视图函数;
JsonResponse 多了一个请求头:'content_type'
:视图函数返回的数据转为json字符串,只是在ajax接收函数返回的数据的时候自己帮你反序列为object对象了;
而 HttpResponse 也是将视图函数返回的数据转为json字符串,但是在ajax接收函数返回的数据的时候需要自己反序列化(json.parse)
from django.http import JsonResponse user = auth.authenticate(username=username, password=pwd) if user: # 用户名密码正确 # 给用户做登录 auth.login(request, user) ret["msg"] = "/index/" else: # 用户名密码错误 ret["status"] = 1 ret["msg"] = "用户名或密码错误!" else: ret["status"] = 1 ret["msg"] = "验证码错误" return JsonResponse(ret)
HTML中:
$.ajax({ url: "/login/", // 进行二次验证 type: "post", dataType: "json", data: { username: $('#inputName3').val(), password: $('#inputPassword3').val(), geetest_challenge: validate.geetest_challenge, geetest_validate: validate.geetest_validate, geetest_seccode: validate.geetest_seccode }, success: function (data) { if (data.status) { $(".login-error").text(data.msg) } else { location.href = data.msg } } });
AJAX请求如何设置csrf_token
第一种是通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
{% csrf_token %} <script> $.ajax({ url: "/cookie_ajax/", type: "POST", data: { "username": "Q1mi", "password": 123456, "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val() // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中 }, success: function (data) { console.log(data); } }) </script>
第二种是自己写插件,把通过获取返回的cookie中的字符串 放置在请求头中发送。
只需要导入js即可以。
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
AJAX的请求的参数
######################------------data---------################ data: 当前ajax请求要携带的数据,是一个json的object对象,ajax方法就会默认地把它编码成某种格式 (urlencoded:?a=1&b=2)发送给服务端;此外,ajax默认以get方式发送请求。 function testData() { $.ajax("/test",{ //此时的data是一个json形式的对象 data:{ a:1, b:2 } }); //?a=1&b=2 ######################------------processData---------################ processData(默认的):声明当前的data数据是否进行转码或预处理,默认为true,即预处理;if为false, 那么对data:{a:1,b:2}会调用json对象的toString()方法,即{a:1,b:2}.toString() ,最后得到一个[object,Object]形式的结果。 ######################------------contentType---------################ contentType:默认值: "application/x-www-form-urlencoded"。发送信息至服务器时内容编码类型。 用来指明当前请求的数据编码格式;urlencoded:?a=1&b=2;如果想以其他方式提交数据, 比如contentType:"application/json",即向服务器发送一个json字符串: $.ajax("/ajax_get",{ data:JSON.stringify({ a:22, b:33 }), contentType:"application/json", type:"POST", }); //{a: 22, b: 33} 注意:contentType:"application/json"一旦设定,data必须是json字符串,不能是json对象 views.py: json.loads(request.body.decode("utf8")) ######################------------traditional---------################ traditional:一般是我们的data数据有数组时会用到 :data:{a:22,b:33,c:["x","y"]}, traditional为false会对数据进行深层次迭代;
request.body是前端传过来的数据。
如果是contentType:"application/json"的类型的,取数据要从request.body取。request.body=b'{"name":"a"}'。
json.loads(request.body.decode("utf8"))
如果是默认的processData,则request.body为b'name=a',默认的帮你把数据按照键值对的形式封装到request.POST里面。
name = request.POST.get("name")
AJAX上传文件
和表单上传文件的意思差不多,对于表单来说,传文件需要添加这一属性
enctype="multipart/form-data"
而对于ajax来说的话:
// 上传文件示例 $("#b3").click(function () { var formData = new FormData(); formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); formData.append("f1", $("#f1")[0].files[0]); $.ajax({ url: "/upload/", type: "POST", processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, // 告诉jQuery不要去设置Content-Type请求头 data: formData, success:function (data) { console.log(data) } }) })
补充:跨域请求
同源策略与Jsonp
同源策略:
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
==================================http://127.0.0.1:8001项目的index <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="http://code.jquery.com/jquery-latest.js"></script> </head> <body> <button>ajax</button> {% csrf_token %} <script> $("button").click(function(){ $.ajax({ url:"http://127.0.0.1:7766/SendAjax/", type:"POST", data:{"username":"yuan","csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()}, success:function(data){ alert(123); alert(data) } }) }) </script> </body> </html> ==================================http://127.0.0.1:8001项目的views def index(request): return render(request,"index.html") def ajax(request): import json print(request.POST,"+++++++++++") return HttpResponse(json.dumps("hello"))
上面的示例因为不满足同源的要求,则执行这个项目的时候会报错,
已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:7766/SendAjax/ 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
说明是浏览器对非同源请求返回的结果做了拦截。
jsonp是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。
<script src="http://127.0.0.1:8008/books/?func=func_name"></script>
这样的形式虽然能进行跨域,但是返回是一个变量,没有意义,做改进就是返回一个函数,把数据(必须是字符串,如果不是字符串的话就在前端报没有定义的错误)放入函数里面,通过调用函数能得到数据。
def books(request): #基于jsonp funcname = request.GET.get("callbacks") data = {"name":"alex","age":32} return HttpResponse("%s('%s')"%(funcname,json.dumps(data)))
<script> function alex(arg){ console.log(arg) } </script>
这样可以实现功能,但是不够灵活,因为代码一执行就进跨域了,因此才用伪造的ajax来实现跨域。
模板中;
$(".btn").on("click", function () { $.ajax({ url: "http://127.0.0.1:8008/books/", type: "get", dataType: "jsonp", //伪造的ajax , 跨域请求,但是本质上还是基于script 上面的原理; jsonp: "callbacks", //k值 , v值(函数名)一般不写,是随机的生成的,即函数名不用自己取; //jsonpCallback:"V值", success: function (arg) { //就相当于上面的函数,arg 就是跨域得到的数据。 var data = JSON.parse(arg); //反序列化#} console.log(typeof data); console.log(data) } } ) })
视图中:
import json # def books(request): #基于jsonp # funcname = request.GET.get("callbacks") # data = {"name":"alex","age":32} # return HttpResponse("%s('%s')"%(funcname,json.dumps(data)))
从原因:CORS 头缺少 'Access-Control-Allow-Origin',可以看出还有一种跨域请求的。
CORS
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
//8000端口的
// 基于cors实现跨域请求 $.ajax({ url: "http://127.0.0.1:8008/books/", type: "get", success: function (arg) { console.log(arg) } }) ;
def books(request): # 基于cors实现跨域请求 data = {"name":"alex","age":32} response = HttpResponse(json.dumps(data)) # response["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000"#(访问的地址) #加到cors头上,即当时这个域名访问的时候就可以拿数据了 response["Access-Control-Allow-Origin"] = "*" #所有的域名访问都可以 return response
支持跨域,简单请求
服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'
补充一个SweetAlert插件示例
$(".btn-danger").on("click", function () { swal({ title: "你确定要删除吗?", text: "删除可就找不回来了哦!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "删除", cancelButtonText: "取消", closeOnConfirm: false }, function () { var deleteId = $(this).parent().parent().attr("data_id"); $.ajax({ url: "/delete_book/", type: "post", data: {"id": deleteId}, success: function (data) { if (data.status === 1) { swal("删除成功!", "你可以准备跑路了!", "success"); } else { swal("删除失败", "你可以再尝试一下!", "error") } } }) }); })