AJAX全称:async javascript and xml
ajax核心作用:实现数据请求+客户端渲染 局部刷新
GET请求方式 params 传参
POST请求方式 在body里传参,支持多种格式
<!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>Document</title>
</head>
<body>
<script src="node_modules/md5/dist/md5.min.js"></script>
<script src="node_modules/qs/dist/qs.js"></script>
<script>
/*
AJAX核心: 基于XMLHttpRequest创建HTTP请求
+ 创建xhr实例
+ 打开一个URL地址 [发送请求前的一些配置信息]
+ method 请求方式:GET(get/delete/head/options...) / POST(post/put/patch)
GET和POST在官方定义中是没有明确的区别的,但是浏览器或者开发的时候,都会有一套约定俗成的规范
> GET请求传递给服务器的信息,除了请求头传递以外,要求基于URL问号传参传递给服务器
xhr.open('GET', './1.JSON?lx=1&name=xxx');
> POST请求要求传递给服务器的信息,是基于请求主体传递
xhr.send('lx=1&name=xxx');
--------------------------------------------------------
(1) GET传递的信息不如POST多,因为URL有长度限制 [IE 2KB],超过这个长度的信息会被自动截掉,这样导致
传递内容过多,最后服务器收到的信息是不完整的!! POST理论上是没有限制的,但是传递的东西越多,速度
越慢,可能导致浏览器传输超时的错误,所以实际上我们会自己动手做限制!!
(2) GET会产生缓存 [浏览器默认产生的,不可控的缓存] :两次及以上,请求相同的API接口,并且传递的参数
也一样,浏览器可能会把第一次请求的信息直接返回,而不是从服务器获取最新的信息
xhr.open('GET', './1.JSON?lx=1&name=xxx&_'+Math.random());
在请求URL的末尾设置随机数,以此来清除GET缓存的副作用
(3) POST相对于GET来讲更安全一些:GET传递的信息是基于URL末尾拼接,这个随便做一些劫持或者修改,都可
以直接改了,而POST请求主体信息的劫持,没那么好做!! 但是"互联网面前,人人都在裸奔"!! 所以不管什么
方式,只要涉及安全的信息,都需要手动加密 [因为默认所有的信息传输都是明文的]
--------------------------------------------------------
+ url 请求的URL地址
+ async 是否采用异步 默认是true
+ username
+ userpass
+ 监听请求的过程,在不同的阶段做不同的处理 [包含获取服务器的响应信息]
+ ajax状态 xhr.readyState
+ 0 UNSENT 未发送
+ 1 OPEND
+ 2 HEADERS_RECEIVED 响应头信息已经返回
+ 3 LOADING 响应主体信息正在处理
+ 4 DONE 响应主体信息已返回
+ HTTP 状态码 xhr.status / xhr.statusText
+ 200 OK
+ 获取响应主体信息 xhr.response/responseText/responseXML...
+ 获取响应头信息 xhr.getResponseHeader/getAllResponseHeaders
+ 发送请求 [send中传递的信息,就是设置的请求主体信息]
基于请求主体传递给服务器的数据格式是有要求的 [Postman接口测试工具]
1. form-data 主要应用于文件的上传或者表达提交
xhr.setRequestHeader('Content-Type', 'multipart/form-data')
------
let fd = new FormData
fd.append('lx', 0)
fd.append('name', 'xxxs')
xhr.send(fd)
2. x-www.form-urlencoded格式的字符串
格式:"lx=1&name=xxx" [常用]
Qs库: $npm i qs
qs.stringify/parse:实现对象的urlencoded格式字符串之间的转换
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
------
xhr.send(Qs.stringify({ lx: 0, name: 'xxx' }))
3. raw 字符串格式
普通字符串 -> text/plain
JSON -> application/JSON => JSON.stringify/parse
XML格式字符串 -> text/xml
....
4. binary 进制数据文件 [buffer/二进制...]
一般也应用于文件上传
图片 -> image/jpeg
EXCEl -> application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
...
5. Graphics
*/
/* let xhr = new XMLHttpRequest();
xhr.open('GET', './1.JSON');
// 设置请求头信息&超时时间&携带资源凭证 需要在open之后send之前
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
// xhr.setRequestHeader('name', '小明'); 请求头信息中不允许出现中文
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
}
xhr.send(null) */
let xhr = new XMLHttpRequest();
xhr.open('GET', 'userInfo?id=1'); // =>router Query
// xhr.open('GET', 'userInfo/1'); // =>router Params
// 后端处理: app.get('/userInfo:id')
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
}
xhr.send(null)
</script>
</body>
</html>
案例:
倒计时抢购
/*
两个时间:
目标时间 18:00:00
当前时间
目标时间-当前时间=时间差 [毫秒差: 计算时间差中包含多少小时,多少分钟,多少秒]
每间隔疫苗中都需要重新获取当前时间 [定时器setInterval],重算时间差等
核心的问题:
当前时间是不可以获取客户端本地的 (因为本地的时间客户自己可以肆意的修改),需要统一获取服务器的时间
[响应头->Date]
+ 获取服务器时间会存在时间偏差问题 --> HEAD AJAX状态码为2
在页面不刷新的情况下,每间隔1秒,不是再次从服务器获取 (如果这样:服务器会崩溃,用户得到的时间误差也会越大...)
而是基于第一次获取的结果之上,手动给其累加到1000ms即可
*/
let countdownMoudle = (function () {
let textBox = document.querySelector('.text'),
serverTime = 0,
targetTime = +new Date('2022/7/22 00:00:00'),
timer = null
// 获取服务器时间
const queryServerTime = function () {
return new Promise((resolve) => {
let xhr = new XMLHttpRequest
xhr.open('HEAD', '/')
xhr.onreadystatechange = () => {
if ((xhr.status >= 200 && xhr.status < 300) && xhr.readyState === 2) {
let time = xhr.getResponseHeader('Date')
// 获取的时间是格林宁时间 -> 变为北京时间
// console.log(new Date(time);
resolve(+new Date(time));
}
}
xhr.send(null)
})
}
// 倒计时计算
const supplyZero = function supplyZero(val) {
val = +val || 0
return val < 10 ? `${val}` : val
}
const computed = function computed() {
let diff = targetTime - serverTime,
hours = 0,
minutes = 0,
seconds = 0
if (diff <= 0) {
// 到达抢购时间了
textBox.innerHTML = '00:00:00';
clearInterval(timer)
return
}
// 没到时间则计算即可
hours = Math.floor(diff / (1000 * 60 * 60))
diff = diff - hours * 1000 * 60 * 60
minutes = Math.floor(diff / (1000 * 60))
diff = diff - minutes * 1000
seconds = Math.floor(diff / 1000)
textBox.innerHTML = `${supplyZero(hours)}:${supplyZero(minutes)}:${supplyZero(seconds)}`
}
return {
async init() {
serverTime = await queryServerTime()
computed()
// 设置定时器
timer = setInterval(() => {
serverTime += 1000
computed()
}, 1000)
}
}
}
)();
countdownMoudle.init()