Python全栈之路-Django(十六)
今日内容:Ajax
http://www.cnblogs.com/wupeiqi/articles/5703697.html
1 Ajax介绍
AJAX,Asynchronous JavaScript and XML (异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案。
1.1异步的JavaScript:
使用 【JavaScript语言】 以及 相关【浏览器提供类库】 的功能向服务端发送请求,当服务端处理完请求之后,【自动执行某个JavaScript的回调函数】。
PS:以上请求和响应的整个过程是【偷偷】进行的,页面上无任何感知。
1.2 XML
XML是一种标记语言,是Ajax在和后台交互时传输数据的格式之一
利用AJAX可以做:
- 注册时,输入用户名自动检测用户是否已经存在。
- 登陆时,提示用户名密码错误
- 删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除。
1.3 Ajax定义总结
偷偷向后台发请求
2 Ajax发送数据
- 原生Ajax,利用XMLHttpRequest对象
- JQuery Ajax,内部基于原生Ajax
- 伪Ajax,非XMLHttpRequest
2.1 原生Ajax
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...
实例:
a. XMLHttpRequest
GET请求:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
alert(xhr.responseText);
}
};
xhr.open('GET','/add2/?i1=12&i2=19');
xhr.send();
POST请求:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
alert(xhr.responseText);
}
};
xhr.open('POST','/add2/');
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send("i1=12&i2=19");
2.2 伪Ajax
伪Ajax,非XMLHttpRequest,利用iframe标签 不刷新打开页面发送HTTP请求
app01.views.py
def fake_ajax(request):
if request.method == 'GET':
return render(request, 'fake_ajax.html')
else:
print(request.POST)
return HttpResponse('...')
templates.fake_ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="f1" action="/fake_ajax/" method="post" target="ifr" >
<iframe id="ifr" frameborder="1" name="ifr" style="display: none;"></iframe>
<input type="text" name="user">
<input type="button" value="提交" onclick="submitForm();">
</form>
<script>
function submitForm() {
document.getElementById('f1').submit();
document.getElementById('ifr').onload = LoadIframe;
}
function LoadIframe() {
var content = document.getElementById('ifr').contentWindow.document.body.innerText
alert(content)
}
</script>
</body>
</html>
2.3 实例
templates.index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<input type="text" id="i1">
+
<input type="text" id="i2">
=
<input type="text" id="i3">
<input type="button" id="btn1" value="JQuery Ajax" onclick="add1();">
<input type="button" id="btn2" value="原生 Ajax" onclick="add2();">
<script src="/static/jquery-3.2.1.min.js"></script>
<script>
function add1() {
$.ajax({
url: '/add1/',
type: 'POST',
data: {'i1': $('#i1').val(),'i2':$('#i2').val()},
success: function (arg) {
$('#i3').val(arg)
}
})
}
function add2() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState ==4){
alert(xhr.responseText);
}
};
// xhr.open('GET','/add2/?i1=12&i2=19');
xhr.open('POST','/add2/');
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send('i1=12&i2=19');
}
</script>
</body>
</html>
app01.views.py
def add1(request):
i1 = int(request.POST.get('i1'))
i2 = int(request.POST.get('i2'))
return HttpResponse(i1+i2)
def add2(request):
if request.method == 'GET':
i1 = int(request.GET.get('i1'))
i2 = int(request.GET.get('i2'))
print(i1+i2)
return HttpResponse(i1+i2)
else:
# i1 = int(request.POST.get('i1'))
# i2 = int(request.POST.get('i2'))
# print(i1 + i2)
print(request.POST)
print(request.body)
return HttpResponse('...')
3 上传文件
- 基于原生Ajax XMLHttpRequest对象
- JQuery Ajax
- 伪Ajax
app01.views.py
import os
def upload(request):
if request.method == 'GET':
return render(request, 'upload.html')
else:
print(request.POST, request.FILES)
file_obj = request.FILES.get('fafafa')
file_path = os.path.join('static', file_obj.name)
print(file_path)
with open(file_path, 'wb') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return HttpResponse(file_path)
templates.upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>原生Ajax上传文件</h1>
<input type="file" id="i1">
<a onclick="upload1();">上传文件</a>
<div id="container1"></div>
<h1>JQuery Ajax上传文件</h1>
<input type="file" id="i2">
<a onclick="upload2();">JQuery Ajax上传文件</a>
<div id="container2"></div>
<h1>伪Ajax上传文件</h1>
<form id="f1" action="/upload/" method="post" target="ifr" enctype="multipart/form-data">
<iframe id="ifr" name="ifr" style="display: none;"></iframe>
<input type="file" id="i3" name="fafafa">
<a onclick="upload3();">伪Ajax上传文件</a>
</form>
<div id="container3"></div>
<script src="/static/jquery-3.2.1.min.js"></script>
<script>
function upload1() {
var formData = new FormData();
formData.append('k1', 'v1');
formData.append('fafafa', document.getElementById('i1').files[0]);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
var file_path = xhr.responseText;
var tag = document.createElement('img');
tag.src = "/"+ file_path;
document.getElementById('container1').appendChild(tag);
}
};
xhr.open('POST','/upload/');
// xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send(formData);
}
function upload2() {
var formData = new FormData();
formData.append('k1', 'v1');
formData.append('fafafa', $('#i2')[0].files[0]);
// DOM对象和JQuery对象的互换
// $('#i2') -> $('#i2')[0]
// document.getElementById('i1') -> $(document.getElementById('i1'))
$.ajax({
url: '/upload/',
type: 'POST',
data: formData,
processData: false, // 让原生的FormData做处理
contentType: false, // 让原生的FormData做处理
success:function (arg) {
var tag = document.createElement('img');
tag.src = "/"+ arg;
$('#container2').append(tag)
}
})
}
function upload3() {
document.getElementById('ifr').onload = loadIframe;
document.getElementById('f1').submit();
}
function loadIframe() {
var content = document.getElementById('ifr').contentWindow.document.body.innerText;
var tag = document.createElement('img');
tag.src = "/"+ content;
$('#container3').append(tag)
}
</script>
</body>
</html>
总结:
伪Ajax兼容性更好(建议上传文件时使用),数据传输时建议使用JQuery
4 JSONP技术
4.1 Ajax存在的问题
- 访问其他域名的URL会被阻止
- 浏览器:
- 同源策略,Ajax跨域发送请求时,再回来时浏览器拒绝接受
- 允许script标签
4.2 JSONP的本质
templates.jsonp.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/static/commons.js"></script>
</head>
<body>
<a onclick="sendMsg();">发送</a>
<script src="/static/jquery-3.2.1.min.js"></script>
<script>
function sendMsg() {
// ajax会存在跨域问题
/*
$.ajax({
url: 'http://dig.chouti.com/',
type: 'GET',
success:function (arg) {
console.log(arg)
}
})
*/
// 报错:XMLHttpRequest cannot load http://dig.chouti.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8001' is therefore not allowed access.
// JSONP
var tag = document.createElement('script');
tag.src = 'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403'; // 返回list(数据)
document.head.appendChild(tag);
}
</script>
</body>
</html>
/static/commons.js
function list(arg) {
console.log(arg);
}