1-Web - Ajax
about
摘自:https://developer.mozilla.org/zh-CN/docs/Glossary/AJAX
Ajax的概念由杰西·詹姆士·贾瑞特所提出,AJAX(Asynchronous JavaScript And XML,异步的JavaScript与XML技术 )是一种使用 XMLHttpRequest 技术构建更复杂,动态的网页的编程实践。
AJAX允许只更新一个 HTML 页面的部分 DOM,而无须重新加载整个页面。AJAX还允许异步工作,这意味着当网页的一部分正试图重新加载时,您的代码可以继续运行(相比之下,同步会阻止代码继续运行,直到这部分的网页完成重新加载)。
通过交互式网站和现代 Web 标准,AJAX正在逐渐被 JavaScript 框架中的函数和官方的 Fetch API 标准取代。
Ajax与XMLHttpRequest
Ajax是一种技术方案,但并不是一种新技术。它依赖的是现有的CSS/HTML/Javascript,而其中最核心的依赖是浏览器提供的XMLHttpRequest对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。
可以总结为:我们使用XMLHttpRequest对象来发送一个Ajax请求。
XMLHttpRequest
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
摘自:阮一峰: XMLHttpRequest Level 2 使用指南
什么是 XMLHttpRequest 对象?
XMLHttpRequest 对象用于在后台与服务器交换数据,最早,微软在IE 5引进了这个接口。因为它太有用,其他浏览器也模仿部署了,ajax操作因此得以诞生。但是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不同(此时可以将XMLHttpRequest划分为 level 1版本)。HTML 5的概念形成后,W3C开始考虑标准化这个接口。2008年2月,就提出了XMLHttpRequest Level 2 草案。
XMLHttpRequest它的优点:
- 在不重新加载页面的情况下更新网页
- 在页面已加载后从服务器请求数据
- 在页面已加载后从服务器接收数据
- 在后台向服务器发送数据
XMLHttpRequest level 1 有以下缺点:
- 受同源策略的限制,不能发送跨域请求。
- 不能发送二进制文件(如图片、视频、音频等),只能发送纯文本数据。
- 在发送和获取数据的过程中,无法实时获取进度信息,只能判断是否完成。
XMLHttpRequest level 2 中做了相应的优化和扩展:
- 可以发送跨域请求,在服务端允许的情况下。
- 支持发送和接收二进制数据。
- 新增formData对象,支持发送表单数据。
- 发送和获取数据时,可以获取进度信息。
- 可以设置请求的超时时间。
来个level 2 版本的GET请求示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMLHttpRequest</title>
</head>
<body>
</body>
<script>
// XMLHttpRequest使用有4个步骤
// 1. 实例化XMLHttpRequest对象, 注意,区分大小写
var xhr = new XMLHttpRequest(); // xhr: ajax对象
// 2. 构建http请求
/* xhr.open(methods, url)
methods: 字符串类型的值,请求类型
url: 字符串类型的值,请求的url
*/
xhr.open('get', 'http://wthrcdn.etouch.cn/weather_mini?city=郑州')
// 3. 发送请求
xhr.send()
// 4. 获取服务端响应数据
xhr.onreadystatechange = function () {
/* xhr.readyState表示xhr的状态码:
1 表示ajx对象刚创建
2 表示ajax请求构建完成
3 表示ajax请求已发送到服务端
4 表示客户端已经获取到服务端返回的数据结果,很明显这个用的多
*/
if(xhr.readyState == 4){
// 一般服务器响应成功返回200
if(xhr.status == 200){
data = JSON.parse(xhr.responseText);
console.log(data);
}else{
console.log(xhr.status);
}
}
}
</script>
</html>
再来个POST请求示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMLHttpRequest</title>
</head>
<body>
</body>
<script>
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://www.httpbin.org/post') // 这个接口有点慢
// post请求如果携带请求数据,就按照下面的示例写
xhr.send("name=zhangkai&age=18")
xhr.onreadystatechange = function () {
if(xhr.readyState == 4){
if(xhr.status == 200){
console.log(xhr.responseText);
}
}
}
</script>
</html>
上面这两个示例,可以说是使用基于JavaScript实现的原生Ajax了。但我们已经很少用到这种原生的Ajax请求了。
jQuery Ajax
jQuery内部也封装了Ajax,使其更简单。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMLHttpRequest</title>
</head>
<body>
</body>
<!-- jQuery中使用Ajax,要先引入jQuery文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
console.log('---------------- get ----------------');
$.ajax({
url: "http://wthrcdn.etouch.cn/weather_mini?city=郑州",
type: "get",
success: function (data) {
data = JSON.parse(data);
console.log(data);
}
});
console.log('---------------- post ----------------');
$.ajax({
url: "http://www.httpbin.org/post", // 请求的url
type: "post", // 请求类型
headers:{ // 携带请求头
k1:"v1",
k2:"v2"
},
data: {"name": "zhangkai", "age": 18}, // 请求携带的data
success: function (data) { // 正确响应走这里
console.log(data);
},
error: function (msg) { // 当遇到服务器400系列或者500系列的响应时,走error
console.log('error:', msg);
}
});
</script>
</html>
示例
Django中Ajax和form表单登录示例
主要文件。
views.py
:
from django.shortcuts import render, redirect, HttpResponse
from django.http import JsonResponse
def login(request):
""" form表单的登录视图函数 """
if request.method == "POST":
user = request.POST.get("username")
pwd = request.POST.get("password")
if user == 'zhangkai' and pwd == "123":
return redirect('/index/')
else:
return render(request, 'login.html', {"username": 'zhangkai', 'password': "123", "msg": "用户名或者密码错误!!!"})
else:
return render(request, 'login.html', {"username": 'zhangkai', 'password': "123"})
def ajax_login(request):
""" ajax的登录视图函数 """
if request.method == "POST":
user = request.POST.get("username")
pwd = request.POST.get("password")
print(11111, user, pwd)
if user == 'zhangkai' and pwd == "123":
return JsonResponse({"status_code": 200, "status_content": "login successful!!!"})
else:
return JsonResponse({"status_code": 201, "status_content": "用户名或者密码错误!!!"})
else:
return render(request, 'login.html', {"username": 'zhangkai', 'password': "123"})
def index(request):
""" 主页 """
return HttpResponse("http 200 ok,懒得写html页面了!!!")
urls.py
:
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index, name='index'),
path('login/', views.login, name='login'),
path('ajax_login/', views.ajax_login, name='ajax_login'),
]
login.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<h1>form表单形式登录</h1>
<form action="" method="post">
{% csrf_token %} <!-- 很重要,不能注释 -->
<input type="text" name="username" value="{{ username }}">
<input type="password" name="password" value="{{ password }}" >
<input type="submit" value="form表单提交">
<span style="color:red">{{ msg }}</span>
</form>
<br>
<h1>AJAX形式登录</h1>
<input type="text" name="username" value="zhangkai" id="user">
<input type="password" name="password" value="123" id="pwd">
<input type="button" value="ajax提交" id="btn">
<span style="color:red" id="msg"></span>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$("#btn").click(function () {
var user = $("#user").val();
var pwd = $("#pwd").val();
$.ajax({
url:"/ajax_login/", // 如果是本地,可以写相对路径
type:"post",
// Ajax仍然受CORS影响,所以要在data中手动的携带csrf_token
data:{"username": user, "password": pwd, "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()},
success:function (data) {
if(data['status_code'] == 200){
window.location.href = '/index/'
}else{
$("#msg").text(data['status_content'])
}
}
})
})
</script>
</html>
Ajax解决跨域问题
Django + jQuery Ajax
urls.py
:
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('test/', views.test, name='test'),
]
前端就有这几种方案。
方案1
在ajax发送请求时,在data中带着csrf_token,不过这需要在body中提前生成token值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<button id="submit">提交</button>
{% csrf_token %} <!-- 就这一行,csrf_token,也可以写在form表单中 -->
</body>
<!-- 首先引入 jQuery -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script>
$('#submit').click(function () {
$.ajax({
url: "/test/",
type: "POST",
data: {"key": "value", "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()},
success: function (data) {
console.log(data)
}
})
})
</script>
</html>
views.py
:
from django.shortcuts import render, redirect, HttpResponse
def test(request):
if request.method == "POST":
print(request.POST) # <QueryDict: {'key': ['value'], 'csrfmiddlewaretoken': ['dVdfgLxEtqTkIE2RfCWRVkMISWV9HJ1dQaxmaGybtZtlnHwcCVUtzuaXvWsoQRF0']}>
return HttpResponse('OK啦')
return render(request, 'test.html')
方案2
这种方式用的也比较多,我们使用jQuery.ajaxSetup()函数帮我们处理。该函数用于为ajax预先设置(更改)一些默认设置。记住,它是全局生效的。如果我们在这个函数中配置关于ajax的一些设置,那么在以后的ajax请求中,都会使用该函数配置的设置。比如,我们可以在这个函数中配置解决跨域的参数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<button id="submit">提交</button>
</body>
<!-- 首先引入 jQuery -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script>
// 预先设置ajax的某些配置,这里配置跨域参数
$.ajaxSetup({
data: {csrfmiddlewaretoken:'{{ csrf_token }}'}
});
// 后续的ajax请求,正常使用即可,无需关心跨域问题
$('#submit').click(function () {
$.ajax({
url: "/test/",
type: "POST",
data: {"key": "value"},
success: function (data) {
console.log(data)
}
})
})
</script>
</html>
views.py
:
from django.shortcuts import render, redirect, HttpResponse
def test(request):
if request.method == "POST":
print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['npWLC80DvGcROnxLMsOQWjOymMhwuZyj0EgSw31avfMStq169LMsAtcNZMOLD7c6'], 'key': ['value']}>
return HttpResponse('OK啦')
return render(request, 'test.html')
方案3
还有一种放在request.META中,但是这种方式需要jquery.cookie.js文件搭配。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<button id="submit">提交</button>
</body>
<!-- 首先引入 jQuery -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<!-- 这种方式必须引入 jquery.cookie.js 文件,这里使用cdn,也可以下载到本地使用 -->
<script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script>
$('#submit').click(function () {
$.ajax({
url: "/test/",
type: "POST",
headers: {"X-CSRFToken": $.cookie('csrftoken'), "zhangkai": 666},
data: {"key": "value"},
success: function (data) {
console.log(data)
}
})
})
</script>
</html>
views.py
:
from django.shortcuts import render, redirect, HttpResponse
def test(request):
if request.method == "POST":
print(request.POST) # <QueryDict: {'key': ['value']}>
print(request.META['HTTP_COOKIE']) # csrftoken=Vnjg1JlDmjOoMPuDbTew9kzcfkv4hP0XyCDnVEmamSoprSYYycc8NuXrSk2jqXEK; jenkins-timestamper-offset=-28800000
print(request.META['CSRF_COOKIE']) # Vnjg1JlDmjOoMPuDbTew9kzcfkv4hP0XyCDnVEmamSoprSYYycc8NuXrSk2jqXEK
print(request.META['HTTP_X_CSRFTOKEN']) # Vnjg1JlDmjOoMPuDbTew9kzcfkv4hP0XyCDnVEmamSoprSYYycc8NuXrSk2jqXEK
return HttpResponse('OK啦')
return render(request, 'test.html')
that's all, see also:
Django基础七之Ajax| http://www.httpbin.org/ | https://www.bootcdn.cn/jquery/ | JS XMLHttpRequest入门教程(非常详细) | w3school: XMLHttpRequest 对象 | https://developer.mozilla.org/zh-CN/docs/Glossary/AJAX | XMLHttpRequest | XMLHttpRequest Level 2 使用指南 | XMLHttpRequest和Ajax | Ajax与XMLHTTPRequest基础理解 | JavaScript之原生Ajax