一、Ajax简介:
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。
- 异步的JavaScript:
使用 【JavaScript语言】 以及 相关【浏览器提供类库】 的功能向服务端发送请求,当服务端处理完请求之后,【自动执行某个JavaScript的回调函数】。
PS:以上请求和响应的整个过程是【偷偷】进行的,页面上无任何感知。 - XML
XML是一种标记语言,是Ajax在和后台交互时传输数据的格式之一 -
利用AJAX可以做:
1、注册时,输入用户名自动检测用户是否已经存在。
2、登陆时,提示用户名密码错误
3、删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除。(博客园)
二:Ajax应用:
1.原生Ajax:

1 //a. XMLHttpRequest 2 3 <!DOCTYPE html> 4 <html lang="en"> 5 <head> 6 <meta charset="UTF-8"> 7 <title>Title</title> 8 </head> 9 <body> 10 <input type="text">+ 11 <input type="text">= 12 <input type="text" id="sum1"> 13 <button type="button" onclick="add1()">提交</button> 14 15 16 <script> 17 function add1() { 18 //创建XMLHttpRequest()对象 19 var xhr = new XMLHttpRequest(); 20 //绑定函数,当对象的状态值变化时会触发 21 xhr.onreadystatechange = function () { 22 //状态值为4,即接收到服务端返回的全部数据,执行后面代码(相当回调函数Jquery中Ajax的success) 23 if (xhr.readyState == 4){ 24 alert(‘执行成功’); 25 //responseText为服务端返回的数据。 26 document.getElementById('sum1').value=xhr.responseText; 27 } 28 }; 29 //GET请求: GET请求数据要放在请求头后端才能收到 30 /*xhr.open('GET','/add1/?i1=12&i2=10''); 31 xhr.send();*/ 32 //POST请求 33 xhr.open('POST',''/add1/'); 34 // 设置请求头,需要这样设置后端才能从request.POST中正常获得数据。 35 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); 36 //发送数据 37 xhr.send("i1=l2&i2=10"); 38 } 39 </script> 40 </body> 41 </html> 42 43 原生Ajax前端代码
1 #后端接收 2 def add1(request): 3 if request.method == "GET": 4 i1 = int(request.GET.get('i1')) 5 i2 = int(request.GET.get('i2')) 6 return HttpResponse(i1+i2) 7 else: 8 print(request.POST) 9 i1 = int(request.POST.get('i1')) 10 i2 = int(request.POST.get('i2')) 11 return HttpResponse(i1+i2)
2.JQuery封装Ajax:........
3.伪Ajax:
数据通过form提交到ifame标签再发送到服务端,同样的,服务端响应的数据也存放于ifame标签中。

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 //target指定提交目标,form不再直接向后台提交,而提交至name=ifr的标签 9 <form id="f1" method="POST" action="/fake_ajax/" target="ifr"> 10 //iframe标签,可以理解为浏览器中的浏览器 11 <iframe id="ifr" name="ifr" style="display: none"></iframe> 12 <input type="text" name="user" /> 13 <a onclick="submitForm();">提交</a> 14 </form> 15 16 <script> 17 /*由于直接在iframe上绑定函数,会导致第一次GET请求时浏览器会报错,所以可以将触发时间绑定在提交按钮标签上, 18 当用户点击提交再给iframe绑定onload匿名函数,此时iframe已经加载完毕所以不会报错,同时给提交按钮赋予提交form 19 数据的功能,当向action的url地址发送POST请求后,返回的响应数据会全部存放于ifame标签中,当onload完成此时iframe 20 中已经包含数据,便可以取到返回数据。*/ 21 function submitForm(){ 22 document.getElementById('ifr').onload = loadIframe; 23 document.getElementById('f1').submit(); 24 /*ifame标签不同于一般标签,可以使用.value或者.innertext取得标签内数据,需要contenWindow进入iframe窗口,随后 25 document.body定位到窗口的body标签取到body的innerText,即真正取到了ifame的数据。 */ 26 } 27 function loadIframe(){ 28 var content = document.getElementById('ifr').contentWindow.document.body.innerText; 29 alert(content); 30 } 31 </script> 32 </body> 33 </html>
4.原生与jquery Ajax上传文件以及伪Ajax上传文件

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <h1>原生Ajax上传文件</h1> 9 <input type="file" id="i1" /> 10 <a onclick="upload1();">上传</a> 11 <div id="container1"></div> 12 13 <h1>jQuery Ajax上传文件</h1> 14 <input type="file" id="i2" /> 15 <a onclick="upload2();">上传</a> 16 <div id="container2"></div> 17 18 <h1>伪 Ajax上传文件</h1> 19 <!-- form表单上传需要加属性 enctype="multipart/form-data" --> 20 <form id="f1" method="POST" action="/upload/" target="ifr" enctype="multipart/form-data"> 21 <iframe id="ifr" name="ifr" style="display: none"></iframe> 22 <input type="file" name="fafafa" /> 23 <a onclick="upload3();">上传</a> 24 </form> 25 <div id="container3"></div> 26 27 <script src="/static/jquery-1.12.4.js"></script> 28 <script> 29 30 //原生JS Ajax 31 function upload1(){ 32 //对于原生Ajax,增添了一个新接口formData,通过它可以以key,value的方式更方便的传送数据 33 //先new一个FormData对象 34 var formData = new FormData(); 35 //通过对象方法append数据,可以是二进制文件。 36 formData.append('k1','v1'); 37 formData.append('fafafa',document.getElementById('i1').files[0]); 38 39 var xhr = new XMLHttpRequest(); 40 /*模拟图片预览功能,当服务端接收到上传的图片并且返回数据,这里返回的是上传文件的存放路径,路径可以当作url 41 访问url即可看到图片,达成预览效果*/ 42 xhr.onreadystatechange = function(){ 43 if(xhr.readyState == 4){ 44 var file_path = xhr.responseText; 45 //创建一个img对象 46 var tag = document.createElement('img'); 47 //img src等于服务端返回的文件路径通过拼接获取正确路径 48 tag.src = "/"+ file_path; 49 //之前预留的div生成标签。 50 document.getElementById('container1').appendChild(tag); 51 } 52 }; 53 xhr.open('POST','/upload/'); 54 //直接send封装好的formData对象 55 xhr.send(formData); 56 } 57 58 //JQuery Ajax 59 function upload2(){ 60 var formData = new FormData(); 61 formData.append('k1','v1'); 62 //由于.files[0]是dom对象方法,所以需要先将jquery对象转换成dom对象即$('#i2') -> $('#i2')[0] 63 // formData.append('fafafa',document.getElementById('i1').files[0]); 64 formData.append('fafafa',$('#i2')[0].files[0]); 65 // $('#i2') -> $('#i2')[0] 66 // document.getElementById('i1') -> $(document.getElementById('i1')) 67 68 $.ajax({ 69 url: '/upload/', 70 type: 'POST', 71 //同样的直接发送formData 72 data: formData, 73 /*由于文件上传时需要contentType属性设置成multipart/form-data,但这里POST方法没有这个属性, 74 所以设置成false修改默认值application/x-www-form-urlencoded,起到一样的效果,这里原理比较深。。*/ 75 contentType:false, 76 //默认为true,默认情况下,发送的数据将被转换为对象,为使数据不被转换,修改为false 77 processData:false, 78 success:function(arg){ 79 var tag = document.createElement('img'); 80 tag.src = "/"+ arg; 81 $('#container2').append(tag); 82 } 83 }) 84 } 85 86 //伪Ajax 87 function upload3(){ 88 document.getElementById('ifr').onload = loadIframe; 89 document.getElementById('f1').submit(); 90 91 } 92 function loadIframe(){ 93 //同样,先获取服务端返回的图像存放路径 94 var content = document.getElementById('ifr').contentWindow.document.body.innerText; 95 var tag = document.createElement('img'); 96 tag.src = "/"+ content; 97 $('#container3').append(tag); 98 } 99 </script> 100 </body> 101 </html>
1 Django后端 2 import os 3 def upload(request): 4 if request.method == "GET": 5 return render(request,'upload.html') 6 else: 7 print(request.POST,request.FILES) 8 # 取到上传的图片 9 file_obj = request.FILES.get('fafafa') 10 # 拼接图片的存放路径 11 file_path = os.path.join("static",file_obj.name) 12 # 循环图片并写到本地路径 13 with open(file_path,'wb') as f: 14 for chunk in file_obj.chunks(): 15 f.write(chunk) 16 # 将写入完成的文件路径发送给客户端查看 17 return HttpResponse(file_path)
由于IE兼容性问题,旧版IE可能不支持FormData,所以上传文件时伪Ajax兼容性会更好一些
三.跨域Ajax
由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。
特别的:由于同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接受罢了。
浏览器同源策略并不是对所有的请求均制约:
- 制约: XmlHttpRequest
- 不叼: img、iframe、script等具有src属性的标签
1.通过JSONP实现跨域请求:

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <input type="button" value="获取用户列表" onclick="getUsers();" /> 9 <ul id="user_list"> 10 11 </ul> 12 <script src="/static/jquery-1.12.4.js"></script> 13 <script> 14 15 //1. 自己写动态创建script 16 function getUsers(){ 17 var tag = document.createElement('script'); 18 tag.src = "http://www.s4.com:8001/users/?callback=bbb"; 19 document.head.appendChild(tag); 20 } 21 22 23 //2. jQuery 24 $.ajax({ 25 url: 'http://www.s4.com:8001/users/', 26 type: 'GET', 27 dataType: 'JSONP', 28 jsonp: 'callback', 29 jsonpCallback: 'bbb' 30 }) 31 32 33 function bbb(arg){ 34 console.log(arg) 35 } 36 /*jsonp String 37 38 在一个jsonp请求中重写回调函数的名字。这个值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分,比如{jsonp:'onJsonPLoad'}会导致将"onJsonPLoad=?"传给服务器。 39 40 jsonpCallback String 41 42 为jsonp请求指定一个回调函数名。这个值将用来取代jQuery自动生成的随机函数名。这主要用来让jQuery生成度独特的函数名,这样管理请求更容易,也能方便地提供回调函数和错误处理。你也可以在想让浏览器缓存GET请求的时候,指定这个回调函数名。 */ 43 44 前端代码
1 #第一个服务端代码,实现跨域的中转站 2 def cors(request): 3 return render(request,'cors.html') 4 5 #第二个,第二次请求数据的服务端 6 def users(request): 7 #获取请求数据,默认是callback=函数名 8 v = request.GET.get('callback') 9 print('请求来了...') 10 user_list = [ 11 'alex','eric','egon' 12 ] 13 user_list_str = json.dumps(user_list) 14 #拼接字符串成为function(arg)的形式发送到前端,arg则为真实需要的数据。 15 temp = "%s(%s)" %(v,user_list_str,) 16 print(temp) 17 return HttpResponse(temp)
注意:JSONP是一种方式,目的解决跨域问题,只能发GET请求,客户端及服务端需约定好请求方式,如callback名称
2.CORS
随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。

1 #简单请求:一次请求 2 3 def new_users(request): 4 obj = HttpResponse('返回内容') 5 #服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*' 6 obj['Access-Control-Allow-Origin'] = "*" 7 return obj 8 #复杂请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只#有“预检”通过后才再发送一次请求用于数据传输。 9 def new_users(request): 10 11 if request.method == "OPTIONS": 12 obj = HttpResponse() 13 obj['Access-Control-Allow-Origin'] = "*" 14 #“预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method 15 obj['Access-Control-Allow-Methods'] = "DELETE" 16 return obj 17 #正常情况同样设置 18 obj = HttpResponse('asdfasdf') 19 obj['Access-Control-Allow-Origin'] = "*" 20 return obj
1 <script> 2 //当type是DELETE时 3 function getUsers(){ 4 $.ajax({ 5 url: 'http://www.s4.com:8001/new_users/', 6 type:"DELETE", 7 success:function(arg){ 8 console.log(arg); 9 } 10 }) 11 } 12 </script>
本文参考:点击这里