Python 20 Ajax全套

时间:2022-05-24 11:23:52

概述

对于web应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上。  

1、传统的Web应用

一个简单操作需要重新加载全局数据

2、AJAX

AJAX,Asynchronous JavaScript and XML (异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案。

  • 异步的JavaScript:
    使用 【JavaScript语言】 以及 相关【浏览器提供类库】 的功能向服务端发送请求,当服务端处理完请求之后,【自动执行某个JavaScript的回调函数】。
    PS:以上请求和响应的整个过程是【偷偷】进行的,页面上无任何感知。
  • XML
    XML是一种标记语言,是Ajax在和后台交互时传输数据的格式之一

利用AJAX可以做:
1、注册时,输入用户名自动检测用户是否已经存在。
2、登陆时,提示用户名密码错误
3、删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除。(博客园)

原生AJAX

Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)。

1、XmlHttpRequest对象介绍

XmlHttpRequest对象的主要方法:

 a. void open(String method,String url,Boolen async)
用于创建请求 参数:
method: 请求方式(字符串类型),如:POST、GET、DELETE...
url: 要请求的地址(字符串类型)
async: 是否异步(布尔类型) b. void send(String body)
用于发送请求 参数:
body: 要发送的数据(字符串类型) c. void setRequestHeader(String header,String value)
用于设置请求头 参数:
header: 请求头的key(字符串类型)
vlaue: 请求头的value(字符串类型) d. String getAllResponseHeaders()
获取所有响应头 返回值:
响应头数据(字符串类型) e. String getResponseHeader(String header)
获取响应头中指定header的值 参数:
header: 响应头的key(字符串类型) 返回值:
响应头中指定的header对应的值 f. void abort() 终止请求

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

2、跨浏览器支持

a、XmlHttpRequest

IE7+, Firefox, Chrome, Opera, etc.

b、ActiveXObject("Microsoft.XMLHTTP")

IE6, IE5

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" onclick="ajax1()" value="提交" />
<script>
// 判断浏览器的对象的方法,可能是XMLHttpRequest,或者是ActiveXObject
function GetXHR() {
var xhr = null;
if (XMLHttpRequest){
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
return xhr;
}
//get类型
{# function ajax1() {#}
{# var xhr = new XMLHttpRequest();#}
{# xhr.open("GET", "/ajax1/", true);#}
{# xhr.onreadystatechange = function() {#}
{# if(xhr.readyState == 4){#}
{# //接收完毕#}
{# var obj = JSON.parse(xhr.responseText);#}
{# console.log(obj);#}
{# }#}
{# };#}
{# xhr.setRequestHeader('key', 'value');#}
{# xhr.send('name=dandy;pwd=123')#}
{# }#} //改成post发送
function ajax1() {
var xhr = GetXHR();
xhr.open("POST", "/ajax1/", true);
xhr.onreadystatechange = function() {
if(xhr.readyState == 4){
//接收完毕
var obj = JSON.parse(xhr.responseText);
console.log(obj);
}
};
xhr.setRequestHeader('key', 'value');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8'); // post的时候的文件头
xhr.send('name=dandy;pwd=123') // 发送数据的格式。
}
</script>
</body>
</html>

在Django里面还是将csrf注释掉,因为楼主没写文件头的csrf_token。post的时候还需要设置一下格式Content-Type之类。

JQuery Ajax

jQuery其实就是一个JavaScript的类库,其将复杂的功能做了上层封装,使得开发者可以在其基础上写更少的代码实现更多的功能。

  • jQuery 不是生产者,而是大自然搬运工。
  • jQuery Ajax本质 XMLHttpRequest 或 ActiveXObject

注:2.+版本不再支持IE9以下的浏览器

 jQuery.get(...)
所有参数:
url: 待载入页面的URL地址
data: 待发送 Key/value 参数。
success: 载入成功时回调函数。
dataType: 返回内容格式,xml, json, script, text, html jQuery.post(...)
所有参数:
url: 待载入页面的URL地址
data: 待发送 Key/value 参数
success: 载入成功时回调函数
dataType: 返回内容格式,xml, json, script, text, html jQuery.getJSON(...)
所有参数:
url: 待载入页面的URL地址
data: 待发送 Key/value 参数。
success: 载入成功时回调函数。 jQuery.getScript(...)
所有参数:
url: 待载入页面的URL地址
data: 待发送 Key/value 参数。
success: 载入成功时回调函数。 jQuery.ajax(...) 部分参数: url:请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒) beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局) accepts:通过请求头发送给服务器,告诉服务器当前客户端课接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式
使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数 如果不指定,jQuery 将自动根据HTTP包MIME信息返回相应类型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string converters: 转换器,将服务器端的内容根据指定的dataType转换类型,并传值给success回调函数
$.ajax({
accepts: {
mycustomtype: 'application/x-some-custom-type'
}, // Expect a `mycustomtype` back from server
dataType: 'mycustomtype' // Instructions for how to deserialize a `mycustomtype`
converters: {
'text mycustomtype': function(result) {
// Do Stuff
return newresult;
}
},
});

jQuery Ajax 方法列表

“伪”AJAX

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

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" onclick="ajax1()" value="提交" />
<input type="text" id="urls" />
<input type="button" value="iframe提交" id="btn" />
<iframe src="http://www.baidu.com" id="ifrm"></iframe>
<script src="/static/jquery-3.2.1.js"></script>
<script>
function GetXHR() {
var xhr = null;
if (XMLHttpRequest){
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
return xhr;
}
{# function ajax1() {#}
{# var xhr = new XMLHttpRequest();#}
{# xhr.open("GET", "/ajax1/", true);#}
{# xhr.onreadystatechange = function() {#}
{# if(xhr.readyState == 4){#}
{# //接收完毕#}
{# var obj = JSON.parse(xhr.responseText);#}
{# console.log(obj);#}
{# }#}
{# };#}
{# xhr.setRequestHeader('key', 'value');#}
{# xhr.send('name=dandy;pwd=123')#}
{# }#}
//改成post发送
function ajax1() {
var xhr = GetXHR();
xhr.open("POST", "/ajax1/", true);
xhr.onreadystatechange = function() {
if(xhr.readyState == 4){
//接收完毕
var obj = JSON.parse(xhr.responseText);
console.log(obj);
}
};
xhr.setRequestHeader('key', 'value');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
xhr.send('name=dandy;pwd=123')
}
$('#btn').click(function() {
var urls1 = $('#urls').val();
console.log(urls1);
$('#ifrm').attr('src',urls1)
})
</script>
</body>
</html>

利用前面的实例,我们继续加上一个iframe标签,然后给一个事件改编iframe内部的src的内容。借助了jquery,给iframe的src重新赋值,发现页面框架也没用刷新。这就相当于iframe也有一个伪ajax,给后台发送请求,并异步刷新了。

讲到这里,是不是可以利用iframe的伪造ajax的原理做点其他事。下面就用iframe做一个异步的form提交。

     <form action="/ajax1/" method="post" target="iframe1">
<iframe name="iframe1"></iframe>
<input type="text" name="username" />
<input type="submit" value="Form提交" />
</form>

iframe form demo

target指向了iframe的name。

Python 20 Ajax全套

总结一下普通的数据提交的推荐优先级:

1、ajax     2、原生的xhr     3、iframe

文件传输

a、XMLHttpRequest:

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.upload{
display: inline-block;
padding: 5px;
background-color: #d0e9c6;
text-align: center;
line-height: 30px;
}
.div1{
position: relative;
width: 100px;
height: 50px;
}
#fafa{
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
opacity: 0;
z-index: 100;
}
</style>
</head>
<body>
<div class="div1">
<input type="file"id="fafa" name="fafa"/>
<a class="upload">上传</a>
</div>
<input type="button" value="xhr提交" onclick="xhrClick()" />
</form>
<script src="/static/jquery-3.2.1.js"></script>
<script>
function xhrClick() {
var file_obj = document.getElementById('fafa').files[0];
var xhr = new XMLHttpRequest();
var fd = new FormData();
fd.append('username','dandy');
fd.append('fafafa', file_obj);
xhr.open('POST', '/upload_test/', true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4){
var obj = JSON.parse(xhr.responseText);
console.log(obj)
}
};
xhr.send(fd)
}
</script>
</body>
</html>

xhr demo

 def upload_test(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':'xxx', 'data':username}
return HttpResponse(json.dumps(ret))

view.py

大家可以好好研究上面的示例里面的上传的样式,主流的网站上很多的上传就是这种格式做出来的。要看一下原理是什么就好。另外前端是通过FormData来封装的数据(append)。

b、JQuery Ajax

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.upload{
display: inline-block;
padding: 5px;
background-color: #d0e9c6;
text-align: center;
line-height: 30px;
}
.div1{
position: relative;
width: 100px;
height: 50px;
}
#fafa{
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
opacity: 0;
z-index: 100;
}
</style>
</head>
<body>
<div class="div1">
<input type="file"id="fafa" name="fafa"/>
<a class="upload">上传</a>
</div>
<input type="button" value="xhr提交" onclick="xhrClick()" />
<input type="button" value="xhr提交" onclick="jqClick()" />
<script src="/static/jquery-3.2.1.js"></script>
<script>
function jqClick() {
var file_obj = document.getElementById('fafa').files[0];
var fd = new FormData();
fd.append('username','dandy');
fd.append('fafafa', file_obj);
$.ajax({
url:'/upload_test/',
type:'POST',
data: fd,
processData:false, // tell jquery not to process the data
contentType:false, // tell jquery not to set contentType
success:function(arg, a1, a2) {
console.log(arg);
console.log(a1);
console.log(a2);
}
})
} function xhrClick() {
var file_obj = document.getElementById('fafa').files[0];
var xhr = new XMLHttpRequest();
var fd = new FormData();
fd.append('username','dandy');
fd.append('fafafa', file_obj);
xhr.open('POST', '/upload_test/', true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4){
var obj = JSON.parse(xhr.responseText);
console.log(obj)
}
};
xhr.send(fd)
}
</script>
</body>
</html>

ajax demo

因为Ajax是对于xhr的封装,所以还是需要借助FormData来封装。另外注意下面2个设置(这2个坑很多人遇到过)。

processData:false, // tell jquery not to process the data

contentType:false, // tell jquery not to set contentType

c、iframe

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.upload{
display: inline-block;
padding: 5px;
background-color: #d0e9c6;
text-align: center;
line-height: 30px;
}
.div1{
position: relative;
width: 100px;
height: 50px;
}
#fafa{
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
opacity: 0;
z-index: 100;
}
</style>
</head>
<body>
<div class="div1">
<input type="file"id="fafa" name="fafa"/>
<a class="upload">上传</a>
</div>
<input type="button" value="xhr提交" onclick="xhrClick()" />
<input type="button" value="xhr提交" onclick="jqClick()" />
<hr/> <form action="/upload_test/" method="POST" enctype="multipart/form-data" target="iframe1">
<iframe id="iframe1" name="iframe1" style="display: none;"></iframe>
<input type="file" name="fafafa">
<input type="submit" onclick="submitForm();" value="iframe提交">
</form>
<script src="/static/jquery-3.2.1.js"></script>
<script>
function jqClick() {
var file_obj = document.getElementById('fafa').files[0];
var fd = new FormData();
fd.append('username','dandy');
fd.append('fafafa', file_obj);
$.ajax({
url:'/upload_test/',
type:'POST',
data: fd,
processData:false, // tell jquery not to process the data
contentType:false, // tell jquery not to set contentType
success:function(arg, a1, a2) {
console.log(arg);
console.log(a1);
console.log(a2);
}
})
} function xhrClick() {
var file_obj = document.getElementById('fafa').files[0];
var xhr = new XMLHttpRequest();
var fd = new FormData();
fd.append('username','dandy');
fd.append('fafafa', file_obj);
xhr.open('POST', '/upload_test/', true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4){
var obj = JSON.parse(xhr.responseText);
console.log(obj)
}
};
xhr.send(fd)
} function submitForm() {
$('#iframe1').on('load', function(){
var text = $('#iframe1').contents().find('body').text();
var obj = JSON.parse(text);
console.log(obj)
})
}
</script>
</body>
</html>

iframe demo

看到这里相信已经很明白了,主流的、更为推荐的传输文件的一定是最后的iframe。

所以传输文件的时候的推荐优先级是

a、iframe        b、ajax        c、xhr

说到这,梳理下上传头像预览的功能:

凭接触的经验可以写出下面的实现操作步骤,需要一个异步操作(iframe来完成),文件保存在服务器上的固定的文件夹内,返回文件路径,网页的图片标签赋值一个路径就ok了。

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.upload{
display: inline-block;
padding: 5px;
background-color: #d0e9c6;
text-align: center;
line-height: 30px;
}
.div1{
position: relative;
width: 100px;
height: 50px;
}
#fafa{
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
opacity: 0;
z-index: 100;
}
</style>
</head>
<body>
<div class="div1">
<input type="file"id="fafa" name="fafa"/>
<a class="upload">上传</a>
</div>
<input type="button" value="xhr提交" onclick="xhrClick()" />
<input type="button" value="xhr提交" onclick="jqClick()" />
<hr/> <form action="/upload_test/" method="POST" enctype="multipart/form-data" target="iframe1">
<iframe id="iframe1" name="iframe1" style="display: none;"></iframe>
<input type="file" name="fafafa">
<input type="submit" onclick="submitForm();" value="iframe提交">
</form>
<img id="iiiimg" />
<script src="/static/jquery-3.2.1.js"></script>
<script>
function jqClick() {
var file_obj = document.getElementById('fafa').files[0];
var fd = new FormData();
fd.append('username','dandy');
fd.append('fafafa', file_obj);
$.ajax({
url:'/upload_test/',
type:'POST',
data: fd,
processData:false, // tell jquery not to process the data
contentType:false, // tell jquery not to set contentType
success:function(arg, a1, a2) {
console.log(arg);
console.log(a1);
console.log(a2);
}
})
} function xhrClick() {
var file_obj = document.getElementById('fafa').files[0];
var xhr = new XMLHttpRequest();
var fd = new FormData();
fd.append('username','dandy');
fd.append('fafafa', file_obj);
xhr.open('POST', '/upload_test/', true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4){
var obj = JSON.parse(xhr.responseText);
console.log(obj)
}
};
xhr.send(fd)
} function submitForm() {
$('#iframe1').on('load', function(){
var text = $('#iframe1').contents().find('body').text();
var obj = JSON.parse(text);
$('#iiiimg').attr('src', '/' + obj.path)
})
}
</script>
</body>
</html>

html demo

 def upload_test(request):
username = request.POST.get('username')
fafafa = request.FILES.get('fafafa')
import os
file_path = os.path.join("static/images", fafafa.name)
with open(file_path, 'wb') as f:
for item in fafafa.chunks():
f.write(item)
ret = {'code':'xxx', 'path':file_path}
return HttpResponse(json.dumps(ret))

view demo

跨域AJAX

由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。

特别的:由于同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接受罢了。

浏览器同源策略并不是对所有的请求均制约:

  • 制约: XmlHttpRequest
  • 不叼: img、iframe、script等具有src属性的标签

这里其实很好发现,比如我们可以直接引用网上的Scriptz,只需要把src指向对应的网址的文件,img同理;iframe本身就是一个异步加载的标签;

这时候我们修改下工作机组

C:\Windows\System32\drivers\etc

Python 20 Ajax全套

hosts文件里面加上一个新的机组dandy,修改django根目录的settings.py

ALLOWED_HOSTS = ['dandy',]

此时测试一下

Python 20 Ajax全套

可以发现,是ok的,现在我们就可以模拟自己给自己发请求了。。

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>JsonP Test</p>
<input type="button" onclick="getContent();" value="获取" />
<script>
function getContent() {
var xhr = new XMLHttpRequest();
xhr.open('GET','http://dandy:8000/app01/jsonp/?name=dandy&ad=111');
xhr.onreadystatechange = function() {
console.log(xhr.responseText);
};
}
</script>
</body>
</html>

HTML

View

先不考虑报错的情况下,我们可以发现

Python 20 Ajax全套

get形式发送的参数,后台都已经接收到了。

现在我们通过script来做

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>JsonP Test</p>
<input type="button" onclick="getContent();" value="获取" />
<script src="/static/jquery-3.2.1.js"></script>
<script>
function getContent() {
var tag = document.createElement('script');
tag.src = 'http://dandy:8000/app01/jsonp/?name=dandy&ad=111';
document.head.appendChild(tag);
document.head.removeChild(tag);
}
function list(arg) {
console.log(arg);
}
</script>
</body>
</html>

发现请求也是可以的,并且返回的ok也是可以接收的。那么就可以借助于script标签就是传输。但是ok字符处理不了,怎么办?

我们将ok改为alert('123')再测试一次

Python 20 Ajax全套

很神奇的发现,原来js代码是可以解析的。

由于浏览器的同源策略,阻止了ajax请求,但是无法阻止script src。

巧妙:

  a、创建script

  b、src=远程地址

  c、返回的数据必须是js格式

此时,我们再对返回的名称就行修改,我们把alert改成callback

 def aaaaa(request):
print(request.GET)
return HttpResponse("callback(123)")

View

这个字符串,是不是就是执行函数?我们再html里面创建function函数是不是就可以执行了?

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>JsonP Test</p>
<input type="button" onclick="getContent();" value="获取" />
<script src="/static/jquery-3.2.1.js"></script>
<script>
function getContent() {
var tag = document.createElement('script');
tag.src = 'http://dandy:8000/app01/aaaaa/?name=dandy&ad=111';
document.head.appendChild(tag);
document.head.removeChild(tag);
} function callback(arg) {
console.log(arg);
}
</script>
</body>
</html>

HTML

是的,这样确实就可以做到了,但是这样有一个不好的地方就是,无法判定别人的api是什么callback函数怎么办?

一般情况下,我们把callback函数也传给api,这样API就可以直接根据callback生成函数返回回来。

tag.src = 'http://dandy:8000/app01/aaaaa/?name=dandy&ad=111&callback=list';

视图函数自定义callback

def aaaaa(request):
print(request.GET)
func = request.GET.get('callback')
return HttpResponse("%s(123)" % func)

好了该讲的都讲完了,下面用实战写一个AJAX的jsonp

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>JsonP Test</p>
<input type="button" onclick="getContent();" value="获取" />
<script src="/static/jquery-3.2.1.js"></script>
<script>
function getContent() {
$.ajax({
url:'http://www.jxntv.cn/data/jmd-jxtv2.html?_=1454376870403',
type:'POST',
dataType:'jsonp',
jsonp:'callback',
jsonpCallback:'list'
});
} function list(arg) {
console.log(arg);
}
</script>
</body>
</html>

HTML

Python 20 Ajax全套

2、CORS

随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。

先贴个blog,有空来补这块、

http://www.cnblogs.com/wupeiqi/articles/5703697.html