06: AJAX全套 & jsonp跨域AJAX

时间:2022-11-03 15:38:55

目录:

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))

views.py视图函数

<!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>

login.html

   3、JQuery ajax借助FormData上传文件(借助FormData低版本ie不支持)

from 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))

views.py

<!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>

upload.html

  4、当框架加载完成发送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函数
}
})
}

当框架加载完成发送ajax获取数据填充页面

1.3 原生ajax(第二种)返回顶部

  1、原生AJAX说明

      1. 原生Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作

      2. 该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)

  2、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...

XmlHttpRequest对象的主要属性

   3、使用原生AJAX发送数据(send方法发送)

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))

views.py视图函数

<!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>

login.html

   4、原生ajax借助FormData上传文件(借助FormData低版本ie不支持)

from 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))

views.py

<!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>

upload.html

1.4 iframe“伪”AJAX(第三种)返回顶部

   1、说明 

      1. 由于HTML标签的iframe标签具有局部加载内容的特性,所以可以使用其来伪造Ajax请求。

   2、使用伪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))

views.py

<!DOCTYPE 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>

login.html

   3、iframe伪ajax上传图片及预览(可以兼容所有浏览器)

from 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')

views.py

<!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>

法1: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>

法2:upload.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打印出来

from django.shortcuts import render,HttpResponse

def get_data(request):
return render(request,'get_data.html')

views.py

<!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>

get_data.html

    2. anotherDomainProject代码

ALLOWED_HOSTS = ['tom.com','127.0.0.1',]

settings.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)

views.py

1.6 在tornado中使用jsonp解决跨域请求返回顶部

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()

app.py

<!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>

get_data.html