什么是AJAX
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
优点:
不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容
不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行
同源策略与jsonp
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
jsonp(jsonpadding)
之前发ajax的时候都是在自己给自己的当前的项目下发
现在我们来实现跨域发。
ajax请求的本质:生成xmlHttpRequest对象
<!DOCTYPE html> <html lang="zh-CN"> <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>index</title><script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script> </head> <body> <form action="" method="" ><input type="text" name="k1" value="v1"><input type="text" name="k2" value="v2"><input id="forms_btn" type="button" value="提交">{% csrf_token %}</form> <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script></body> </html>
下面是,前端以json格式 发往后端的JavaScript代码
<script>$("#forms_btn").click(function () {$.ajax({url:"/fromData/",type:"post",dataType:"json", // 注意 :是预期服务器返回的数据类型
headers:{"X-CSRFToken":$("[name='csrfmiddlewaretoken']").val()},contentType:"application/json",data:{"name":$("[name='k1']").val(),"name":$("[name='k2']").val(),},})})
</script>
注意:
1、设置contentType:默认编码格式 “url_encoding” ?a=1&b=2
2、设置headers
3、data, 在后端接受到是以二进制形式(b'password=v1&name=v2'),需要反序列化
前端的JavaScript data{“a”:1,“b”:2}, 其中a,b 可以不用提前定义,就使用,所以可以这样使用:data{a:1,b:2}和Python不同
4、后台取数据不能在POST中取,需要在body中取
dataType
前端设置dataType ,后端如果返回的非json数据,后端不能识别,但是不报错,
使用Ajax跨域
view层
def ajax_send(request):func=request.GET.get("callback")print("func",func)res={"name":"alex"}import jsonreturn HttpResponse("%s('%s')"%(func,json.dumps(res)))
ajax 无法跨域访问其他网站,
<script>$(".b1").click(function () {$.ajax({url:"http://127.0.0.1:8002/ajax_send/", // 浏览器的同源策略的原因,AJax无法发送跨域请求 success:function (data) {alert(data)}})}); </script>
下面看如何解决跨域访问
跨域访问初级版
<script>function foo(s) {console.log(s);JSON.parse(s)}function kua_yu(url) {// 生成 script标签var $ele_script=$("<script>"); 注意:使用了 $ele_script创建标签$ele_script.attr("src",url);$ele_script.attr("class","kuayu");// 添加到body中 $("body").append($ele_script); // 发送请求 $(".kuayu").remove() // 生成之后即删除,不会产生多余的标签}$(".b2").click(function () {kua_yu( "http://127.0.0.1:8002/ajax_send/?callback=foo")}); </script>
跨域访问进阶版
$(".b1").click(function () {$.getJSON("http://127.0.0.1:8002/ajax_send/?callback=?",function (data) { // function 使用了回调函数,console.log(data);})
});
要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个?是内部自动生成的一个回调函数名
跨域访问高级版
<script> $(".b1").click(function () {$.ajax({url:'http://127.0.0.1:8002/ajax_send/',dataType:"jsonp",jsonp: 'callback',jsonpCallback:"SayHi"}); });$(".b2").click(function () {$.ajax({url:'http://www.jxntv.cn/data/jmd-jxtv2.html?',dataType:"jsonp",jsonp: 'callback',jsonCallback:"list" // 访问的函数名,可定制});});function list(data) {console.log(data.data);$.each(data.data,function (i,weekday) {//console.log(j); // {week: "周日", list: Array(19)} $("body").append("<p>"+weekday.week+"</p>");console.log(weekday.list);$.each(weekday.list,function (j,show) {s="<p><a href='"+show.link+"'>"+show.name+"</a></p>"$("body").append(s);})})}</script>
注意:jsonp 一定是GET请求
csrf跨站请求伪造
如果把type:"GET" 改为type:"POST" 会报一个Forbidden的错
解决办法有三种:
方式一:
$.ajaxSetup({data:{csrfmiddlewaretoken:'{{ csrf_token }}'}});注意:要放在ajax请求的前面,在发送之前组装一组字符串,在第一步render的时候就发了所以有局限性:如果把JS代码放到静态文件中,不会渲染,不会执行{{csrf_token}},只能在HTML页面中使用
方式二:自己组装一组键值对 ( 推荐)
<form>
{% csrf_token %}
</form>data:{csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),name:$(":text").val(),pwd:$(":password").val()},
方式三:自己设置头信息
<script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
$.ajax({url:"/serialize/",type:"POST",headers:{"X-CSRFToken":$.cookie('csrftoken')},})
jQuery.serialize()
serialize()
函数用于序列化一组表单元素,将表单内容编码为用于提交的字符串。
serialize()
函数常用于将表单内容序列化,以便用于AJAX提交。
该函数主要根据用于提交的有效表单控件的name和value,将它们拼接为一个可直接用于表单提交的文本字符串,该字符串已经过标准的URL编码处理(字符集编码为UTF-8)。
该函数不会序列化不需要提交的表单控件,这和常规的表单提交行为是一致的。例如:不在<form>标签内的表单控件不会被提交、没有name属性的表单控件不会被提交、带有disabled属性的表单控件不会被提交、没有被选中的表单控件不会被提交。
与常规表单提交不一样的是:常规表单一般会提交带有name的按钮控件,而serialize()函数不会序列化带有name的按钮控件。更多详情请点击这里。
语法:
jQueryObject.serialize( )
serialize()
函数的返回值为String类型,返回将表单元素编码后的可用于表单提交的文本字符串。
请参考下面这段初始HTML代码:
<form name="myForm" action="http://www.365mini.com" method="post"><input name="uid" type="hidden" value="1" /><input name="username" type="text" value="张三" /><input name="password" type="text" value="123456" /><select name="grade" id="grade"><option value="1">一年级</option><option value="2">二年级</option><option value="3" selected="selected">三年级</option><option value="4">四年级</option><option value="5">五年级</option><option value="6">六年级</option></select><input name="sex" type="radio" checked="checked" value="1" />男<input name="sex" type="radio" value="0" />女<input name="hobby" type="checkbox" checked="checked" value="1" />游泳<input name="hobby" type="checkbox" checked="checked" value="2" />跑步<input name="hobby" type="checkbox" value="3" />羽毛球<input name="btn" id="btn" type="button" value="点击" /> </form>
对<form>元素进行序列化可以直接序列化其内部的所有表单元素。
// 序列化<form>内的所有表单元素 // 序列化后的结果:uid=1&username=%E5%BC%A0%E4%B8%89&password=123456&grade=3&sex=1&hobby=1&hobby=2 alert( $("form").serialize() );
我们也可以直接对部分表单元素进行序列化。
// 序列化所有的text、select、checkbox表单元素 // 序列化后的结果:username=%E5%BC%A0%E4%B8%89&password=123456&grade=3&hobby=1&hobby=2 alert( $(":text, select, :checkbox").serialize() );
示例:
<!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"><title>Title</title> </head> <body> <form name="myForm" action="http://www.365mini.com" method="post"><input name="uid" type="hidden" value="1" /><input name="username" type="text" value="张三" /><input name="password" type="text" value="123456" /><select name="grade" id="grade"><option value="1">一年级</option><option value="2">二年级</option><option value="3" selected="selected">三年级</option><option value="4">四年级</option><option value="5">五年级</option><option value="6">六年级</option></select><input name="sex" type="radio" checked="checked" value="1" />男<input name="sex" type="radio" value="0" />女<input name="hobby" type="checkbox" checked="checked" value="1" />游泳<input name="hobby" type="checkbox" checked="checked" value="2" />跑步<input name="hobby" type="checkbox" value="3" />羽毛球<input name="btn" id="btn" type="button" value="点击" /> </form> <script src="/static/jquery-3.2.1.min.js"></script> <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script> <script>$("#btn").click(function () { {# 方式一#}//$.ajaxSetup({// data:{csrfmiddlewaretoken:'{{ csrf_token }}'}//}); $.ajax({url:"/serialize/",type:"POST", {# 方式三#}headers:{"X-CSRFToken":$.cookie('csrftoken')},//data:$("form").serialize(), //序列form表单所有的 data:$(":text,:password,:checkbox").serialize(), //序列自己选择的 success:function (data) {var data=JSON.parse(data); //js中的反序列化 console.log(data);console.log(typeof data);$(".error").html(data);}})}) </script> </body> </html>serialize.html
1 def serialize(request): 2 # form = request.POST 3 # print(form) 4 name = request.POST.get("username") 5 password = request.POST.get("password") 6 checked = request.POST.getlist("hobby") 7 print(name,password,checked) 8 return HttpResponse(json.dumps(name))
当有好多input的时候,就得一一对应的吧所有的数据发过去的,这样显得麻烦,我们用序列化 jQuery.serialize()data:$("form").serialize(), //序列form表单所有的 data:$(":text,:password,:checkbox").serialize(), //序列自己选择的在服务端获取数据 form = request.POST print(form) #获取所有 name = request.POST.get("username") password = request.POST.get("password") checked = request.POST.getlist("hobby") print(name,password,checked)#获取单个
Ajax上传文件(利用FormData)
既可以处理二进制,又可以处理字典,列表啊等
FormData是什么呢?
FormData
.利用FormData对象
,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()
方法来异步的提交这个"表单".比起普通的ajax,使用FormData
的最大优点就是我们可以异步上传一个二进制文件.$("#upload") 拿到的是一个集合 $("#upload")[0] 就是一个dom对象 $("#upload")[0].files 拿到的是一个filelist $("#upload")[0].files[0] 拿到的是当前最近的文件对象
要是使用FormData一定要加上:
一定要加上:
contentType:false
processDate:false #不做预处理
ajaxupload.html
<!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"><title>Title</title> </head> <body> <p>姓名<input type="text" name="username"></p> <p>头像<input type="file" id="upload"></p> <p><button class="btnnn">提交</button><span class="tishi"></span></p> <script src="/static/jquery-3.2.1.min.js"></script> <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script> <script>$(".btnnn").click(function () {var formData=new FormData();formData.append("username",$(":text").val());formData.append("file",$("#upload")[0].files[0]);$.ajax({url:"/get_upload/",type:"POST",headers:{"X-CSRFToken":$.cookie('csrftoken')},data:formData,contentType:false,processData:false,success:function (data) {$(".tishi").html("上传成功")}})}) </script> </body> </html>
view.py
def ajaxupload(request):return render(request,"ajaxupload.html")def get_upload(request):if request.method == "POST":print("FIFLE", request.FILES)file_obj = request.FILES.get("file")print(file_obj.name, "-----")file_obj = request.FILES.get("file")with open(file_obj.name, "wb") as f:for i in file_obj:f.write(i)return HttpResponse("上传成功")