06: AJAX全套 & jsonp跨域AJAX
目录:
- 1.1 AJAX介绍
- 1.2 jQuery AJAX(第一种)
- 1.3 原生ajax(第二种)
- 1.4 iframe“伪”AJAX(第三种)
- 1.5 jsonp跨域请求
- 1.6 在tornado中使用jsonp解决跨域请求
1.1 AJAX介绍
1、AJAX作用
1. AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
2. AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
3. AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
2、AJAX与传统开发模式区别
ajax开发模式:页面将用户的操作通过ajax引擎与服务器进行通信,将返回的结果给ajax引擎,然后ajax将数据插入指定位置。
传统的开发模式:用户的每一次操作都触发一次返回服务器的HTTP请求,服务器做出处理后,返回一个html页面给用户。
3、AJAX请求的三种方法
1. jQuery Ajax:本质 XMLHttpRequest 或 ActiveXObject
2. 原生Ajax:主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在
3. “伪”AJAX:由于HTML标签的iframe标签具有局部加载内容的特性,所以可以使用其来伪造Ajax请求
1.2 jQuery AJAX(第一种)
1、JQuery AJAX说明
1、jQuery其实就是一个JavaScript的类库,其将复杂的功能做了上层封装,使得开发者可以在其基础上写更少的代码实现更多的功能
2、jQuery Ajax本质 XMLHttpRequest 或 ActiveXObject
2、使用JQuery AJAX发送数据
from django.shortcuts import render,HttpResponse import json def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method == 'POST': print(request.POST) #{'name': ['root'], 'pwd': ['123']} ret = {'code':True,'data':None} return HttpResponse(json.dumps(ret))login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form id="add_form"> <input type="text" name="user" placeholder="用户名"> <input type="text" name="pwd" placeholder="密码"> <span id="jquery_ajax">JQuery Ajax提交</span> </form> <script src="/static/jquery-1.12.4.js"></script> <script> $('#jquery_ajax').click(function(){ $.ajax({ url: '/login/', // data: {'user': 123,'host_list': [1,2,3,4]}, // 也可以这样穿数据给后台 data: $('#add_form').serialize(), //拿到form表单提交的所有内容 type: "POST", dataType: 'JSON', // 让JQuery将data先JSON后再发送到后台 traditional: true, //如果发送的是列表告诉JQuery也发送到后台 success: function(data, statusText, xmlHttpRequest){ if(data.code == true){ console.log('返回登录后的页面'); }else { console.log('在页面上添加错误提示信息'); } }, error: function () { //只有当发送数据,后台没有捕捉到的未知错误才执行error函数 } }) }); </script> </body> </html>
3、JQuery ajax借助FormData上传文件(借助FormData低版本ie不支持)
views.pyfrom django.shortcuts import render,HttpResponse import json def upload(request): return render(request,'upload.html') def upload_file(request): username = request.POST.get('username') fafafa = request.FILES.get('fafafa') print(username,fafafa) with open(fafafa.name,'wb') as f: for item in fafafa.chunks(): f.write(item) ret = {'code':True,'data':request.POST.get('username')} return HttpResponse(json.dumps(ret))upload.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .upload{ display: inline-block; padding: 10px; background-color: brown; position: absolute; top: 0; bottom: 0; left: 0; right: 0; z-index: 90; } .file{ width: 60px; height: 30px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; z-index: 100; opacity: 0; } </style> </head> <body> {# 为了让我们的上传图标好看,可以用我们的a标签显示到上传标签的外面 #} <div style="position: relative;width: 60px;height: 40px"> <input class="file" type="file" id="fafafa" name="afafaf"> <a class="upload">上传</a> </div> <input type="button" value="提交jQuery" onclick="fqSubmit();"> <script src="/static/jquery-1.12.4.js"></script> <script> function fqSubmit(){ var file_obj = document.getElementById('fafafa').files[0]; var fd = new FormData(); // FormData对象可以传字符串,也可以传文件对象 fd.append('username','root'); fd.append('fafafa',file_obj); var xhr = new XMLHttpRequest(); $.ajax({ url:'/upload_file/', type:'POST', data:fd, //jquery Ajax上传文件必须执定processData,contentType参数 processData:false, //告诉JQuery不要特殊处理这个数据 contentType:false, //告诉JQuery不要设置内容格式 success:function(arg,a1,a2){ console.log(111,arg); //后台返回的数据 console.log(222,a1); //执行状态:sucess(fail) console.log(333,a2); //对象 } }) } </script> </body> </html>
4、当框架加载完成发送ajax发送请求获取数据
当框架加载完成发送ajax获取数据填充页面// 当框架加载完成后执行此函数 window.onload = function(){ var deptid = $('[name="approvetype"]').val(); $.ajax({ url: '{% url "workordermanager:parse_deptid" %}', data: {'deptid': deptid}, // 也可以这样穿数据给后台 type: "get", dataType: 'JSON', // 让JQuery将data先JSON后再发送到后台 traditional: true, //如果发送的是列表告诉JQuery也发送到后台 success: function(data, statusText, xmlHttpRequest){ if(data.code == true){ $('[name="approvetype"]').val(data.data); }else { console.log('在页面上添加错误提示信息'); } }, error: function () { //只有当发送数据,后台没有捕捉到的未知错误才执行error函数 } }) }
1.3 原生ajax(第二种)
1、原生AJAX说明
1. 原生Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作
2. 该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)
2、XmlHttpRequest对象方法和属性
XmlHttpRequest对象的主要方法// 1、void open(String method,String url,Boolen async) 1)作用:用于创建请求 2)参数: method: 请求方式(字符串类型),如:POST、GET、DELETE... url: 要请求的地址(字符串类型) async: 是否异步(布尔类型) // 2、void send(String body) 1)作用:用于发送请求 2)参数: body: 要发送的数据(字符串类型) // 3、void setRequestHeader(String header,String value) 1)作用:用于设置请求头 2)参数: header: 请求头的key(字符串类型) vlaue: 请求头的value(字符串类型) // 4、String getAllResponseHeaders() 1)作用:获取所有响应头 2)返回值: 响应头数据(字符串类型) // 5、String getResponseHeader(String header) 1)作用:获取响应头中指定header的值 2)参数: header: 响应头的key(字符串类型) 3)返回值: 响应头中指定的header对应的值 // 6、oid abort() 1)作用: 终止请求XmlHttpRequest对象的主要属性
//a. Number readyState 状态值(整数) 详细: 0-未初始化,尚未调用open()方法; 1-启动,调用了open()方法,未调用send()方法; 2-发送,已经调用了send()方法,未接收到响应; 3-接收,已经接收到部分响应数据; 4-完成,已经接收到全部响应数据; //b. Function onreadystatechange 当readyState的值改变时自动触发执行其对应的函数(回调函数) //c. String responseText 服务器返回的数据(字符串类型) //d. XmlDocument responseXML 服务器返回的数据(Xml对象) //e. Number states 状态码(整数),如:200、404... //f. String statesText 状态文本(字符串),如:OK、NotFound...
3、使用原生AJAX发送数据(send方法发送)
views.py视图函数from django.shortcuts import render,HttpResponse import json def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method == 'POST': print(request.POST) #{'name': ['root'], 'pwd': ['123']} ret = {'code':True,'data':None} return HttpResponse(json.dumps(ret))
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="ajax1" onclick="Ajax1()"> <script> // 使用原生ajax发送数据 function Ajax1(){ // var xhr = GetXHR(); //(浏览器兼容性可以这样创建xhr对象) //1 new关键字创建JavaScript的XMLHttpRequest对象xhr var xhr = new XMLHttpRequest(); //创建xhr对象(浏览器兼容性) //2 以get方式发数据给ajax_json,true表示支持异步 xhr.open('POST','/login/',true); //open就是xhr对象的方法 //3 onreadystatechange是:回调函数,当readyState的值改变时自动触发执行其对应的匿名函数 xhr.onreadystatechange = function(){ if(xhr.readyState == '4'){ // 只有状态为4时才执行 表示已经接收完毕 var obj = JSON.parse(xhr.responseText); // xhr.responseText就是服务器端的返回值 console.log(obj); //获取返回值:{code: true, data: null} } }; //4 发送请求头 CSRF中用的就是这个 xhr.setRequestHeader('k1','v1'); //5 后台要想获得xhr.send数据,必须在这里设置请求头 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8'); //6 发送的字符串内容 xhr.send("name=root;pwd=123"); } // 原生ajax兼容ie低版本才使用这个方法创建XMLHttpRequest对象 function GetXHR(){ var xhr = null; //先设置xhr对象为null if(XMLHttpRequest){ xhr = new XMLHttpRequest(); //如果有XMLHttpRequest就设置 }else{ xhr = new ActiveXObject("Microsoft.XMLHTTP"); //没有就设置成微软的 } return xhr; } </script> </body> </html>
4、原生ajax借助FormData上传文件(借助FormData低版本ie不支持)
views.pyfrom django.shortcuts import render,HttpResponse import json def upload(request): return render(request,'upload.html') def upload_file(request): username = request.POST.get('username') fafafa = request.FILES.get('fafafa') print(username,fafafa) with open(fafafa.name,'wb') as f: for item in fafafa.chunks(): f.write(item) ret = {'code':True,'data':request.POST.get('username')} return HttpResponse(json.dumps(ret))upload.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .upload{ display: inline-block; padding: 10px; background-color: brown; position: absolute; top: 0; bottom: 0; left: 0; right: 0; z-index: 90; } .file{ width: 60px; height: 30px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; z-index: 100; opacity: 0; } </style> </head> <body> {# 为了让我们的上传图标好看,可以用我们的a标签显示到上传标签的外面 #} <div style="position: relative;width: 60px;height: 40px"> <input class="file" type="file" id="fafafa" name="afafaf"> <a class="upload">上传</a> </div> <input type="button" value="提交XHR" onclick="xhrSubmit();"> <script src="/static/jquery-1.12.4.js"></script> <script> // 原生ajax上传文件 function xhrSubmit(){ var file_obj = document.getElementById('fafafa').files[0]; var fd = new FormData(); // FormData对象可以传字符串,也可以传文件对象 fd.append('username','root'); fd.append('fafafa',file_obj); var xhr = new XMLHttpRequest(); xhr.open('POST','/upload_file/',true); //open就是xhr对象的方法 xhr.onreadystatechange = function(){ if(xhr.readyState == '4'){ var obj = JSON.parse(xhr.responseText); console.log(obj); } }; xhr.send(fd); } </script> </body> </html>
1.4 iframe“伪”AJAX(第三种)
1、说明
1. 由于HTML标签的iframe标签具有局部加载内容的特性,所以可以使用其来伪造Ajax请求。
2、使用伪AJAX发送数据
views.pyfrom django.shortcuts import render,HttpResponse import json def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method == 'POST': print(request.POST) #{'name': ['root'], 'pwd': ['123']} ret = {'code':True,'data':None} return HttpResponse(json.dumps(ret))login.html
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {#1 target="ifm1 就让form和iframe建立关系,表单就会通过iframe提交数据到后台 #} {#2 可以给submit绑定一个事件,当点击时才绑定iframeLoad事件 #} <form action="/login/" method="POST" target="ifm1"> <iframe name="ifm1" id="ifm1" style="display: none"></iframe> <input type="text" name="username"> <input type="text" name="email"> <input type="submit" value="Form提交" onclick="submitForm();"> </form> <script src="/static/jquery-1.12.4.js"></script> <script> //1 使用iframe提交数据,后台返回数据放到iframe中了,需要拿到数据 //2 只有当点击提"Form提交"才会触发绑定iframe 的load事件 //3 只有当后台返回数据后,才会自动触发iframe的load事件 function submitForm(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); // contents()中就可以获取到后台返回给iframe的内容了 var obj = JSON.parse(text); //将字符串转换成json数据 console.log(obj) }) } </script> </body> </html>
3、iframe伪ajax上传图片及预览(可以兼容所有浏览器)
views.pyfrom django.shortcuts import render,HttpResponse import json import os def upload_file(request): if request.method == 'POST': username = request.POST.get('username') fafafa = request.FILES.get('fafafa') img_path = os.path.join('static\image',fafafa.name) print(img_path) with open(img_path,'wb') as f: for item in fafafa.chunks(): f.write(item) ret = {'code':True,'data':img_path} return HttpResponse(json.dumps(ret)) return render(request,'upload_file.html')法1:upload.html不定义上传按钮样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/upload_file/" method="POST" target="ifm1" enctype="multipart/form-data"> <iframe name="ifm1" id="ifm1" style="display: none"></iframe> <input type="file" name="fafafa"> <input type="submit" value="iframe提交" onclick="iframeForm();"> </form> <div id="preview"></div> <script src="/static/jquery-1.12.4.js"></script> <script> function iframeForm(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); //将字符串转换成json数据 var imgTag = document.createElement('img'); //创建image标签 $('#preview').empty(); imgTag.src='/'+obj.data; //上传后图片路径 $('#preview').append(imgTag); }) } </script> </body> </html>法2:upload.html自定义上传按钮样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form id="fm" action="/upload_file/" method="POST" target="ifm1" enctype="multipart/form-data"> <iframe name="ifm1" id="ifm1" style="display: none"></iframe> <input type="file" name="fafafa" onchange="iframeForm();" id="publish_file" style="display: none"> <a onclick="document.getElementById('publish_file').click();">上传图片</a> </form> <div id="preview"></div> <script src="/static/jquery-1.12.4.js"></script> <script> function iframeForm(){ $('#ifm1').load(function(){ var text = $('#ifm1').contents().find('body').text(); var obj = JSON.parse(text); //将字符串转换成json数据 var imgTag = document.createElement('img'); //创建image标签 $('#preview').empty(); imgTag.src='/'+obj.data; //上传后图片路径 $('#preview').append(imgTag); }); document.getElementById('fm').submit(); } </script> </body> </html>
1.5 jsonp跨域请求
1、jsonp跨域请求原理
1. 由于浏览器存在同源策略机制,同源策略阻止通过js通过浏览器设置另一个源加载的文档的属性。
2. 比如现在访问 http://127.0.01/index 页面,在index页面中通过js发送请求获取 http://tom.com/login/ 页面的数据会被浏览器阻止
3. 由于同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接受返回来的数据罢了
4. 浏览器同源策略仅制约XmlHttpRequest,不会制约 img、iframe、script等具有src属性的标签
5. JSONP(JSON with Padding是JSON的一种“使用模式”),利用script标签的src属性实现jsonp跨域请求
6. JSONP实质就是通过scrip的src属性向其他域请求数据,这样就可以在网页中获取到远端路径的数据了
2、实现jsonp跨域请求测试分为以下几步
1. 首先需要建立第两个Django项目MyNewDay25 和 anotherDomainProject
2.从MyNewDay25 的Django项目通过AJAX,向 anotherDomainProject项目请求数据
3. 这里因为在同一台计算机中测试,所以将anotherDomainProject 监听端口改为8001
4. 为了实现不同域名的效果,修改计算机hosts记录:
路径: C:\Windows\System32\drivers\etc\hosts
添加: 127.0.0.1 tom.com
目的:通过 http://tom.com:8001/another_domain_project/?callback=list' 访问anotherDomainProject
2、MyNewDay25 项目中发送请求给anotherDomainProject获取数据
1. MyNewDay25代码
说明:当我们访问MyNewDay25项目的: http://127.0.0.1:8000/get_data/ 时就会使用ajax到
http://tom.com:8001/another_domain_project/ 获取数据,然后通过console.log打印出来
views.pyfrom django.shortcuts import render,HttpResponse def get_data(request): return render(request,'get_data.html')get_data.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="获取数据" onclick="getContent();" /> <script src="/static/jquery-1.12.4.js"></script> <script> function getContent(){ // 1. 使用原生js的src属性跨域请求数据 var tag = document.createElement('script'); tag.src = 'http://tom.com:8001/another_domain_project/?callback=list'; // tag.src = 'http://www.jxntv.cn/data/jmd-jxtv2.html?calback=list&_=1454376870403'; document.head.appendChild(tag); document.head.removeChild(tag); // 2. 使用ajax实现jsonp跨域请求 $.ajax({ url: 'http://tom.com:8001/another_domain_project/', type: 'POST', dataType: 'jsonp', // 下面的两句就相当于上面再URL中写:?callback=list jsonp: 'callback', jsonpCallback: 'list' }) } // 3.这个函数就是当数据返回后使用list函数处理:arg就是跨域请求来的数据 function list(arg){ console.log(arg); } </script> </body> </html>
2. anotherDomainProject代码
settings.pyALLOWED_HOSTS = ['tom.com','127.0.0.1',]views.py
from django.shortcuts import render,HttpResponse def another_domain_project(request): # 请求端发送AJAX请求路径:http://tom.com:8001/another_domain_project/?callback=list func = request.GET.get('callback') # 获取请求端回调函数名(这里名字是:list,字符串格式) content = '%s(1000000)'%(func) # 返回给请求端内容:list(1000000), 在请求端就会调用js中的list()函数了 return HttpResponse(content)
1.6 在tornado中使用jsonp解决跨域请求
app.py
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.set_header('Access-Control-Allow-Origin', "") self.render('get_data.html') settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', } application = tornado.web.Application([ (r"/get_date", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8000) print('http://127.0.0.1:8000/get_date') tornado.ioloop.IOLoop.instance().start()get_data.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <input type="button" onclick="AjaxRequest()" value="跨域Ajax" /> <div id="container"></div> <script src="/static/jquery-1.12.4.js" type="text/javascript"></script> <script type="text/javascript"> function AjaxRequest() { $.ajax({ // 下面这个路径是江西卫视界面菜单的json数据 url: 'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403', type: 'GET', dataType: 'jsonp', jsonp: 'callback', jsonpCallback: 'list', success: function (data) { $.each(data.data,function(i){ var item = data.data[i]; var str = "<p>"+ item.week +"</p>"; $('#container').append(str); $.each(item.list,function(j){ var temp = "<a href='" + item.list[j].link +"'>" + item.list[j].name +" </a><br/>"; $('#container').append(temp); }); $('#container').append("<hr/>"); }) } }); } </script> </body> </html>