目录
一、原生AJAX
1.1AJAX 简介
1.2 XML 简介
1.3 AJAX的特点
二、HTTP协议
三、AJAX案例准备工作
四、发送AJAX请求
1.发送GET请求
2.发送POST请求
3.JSON响应
IE缓存问题:
五、AJAX 请求状态
一、原生AJAX
-
1.1AJAX 简介
AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式
比如百度搜索框:
搜索abcd,下面出现的提示框就是用到Ajax,提示框中的信息不是自动生成的,而是向服务器发送请求,数据从服务器返回。
注册页面:
当我们输入一个用户名,不可以时,会提示此用户名太受欢迎,请更换一个,也是运用了Ajax。
-
1.2 XML 简介
XML 可扩展标记语言。XML 被设计用来传输和存储数据。XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据。(现在已经被 JSON 取代了。)
-
1.3 AJAX的特点
1.3.1 AJAX的优点
1) 可以无需刷新页面而与服务器端进行通信。
2) 允许你根据用户事件来更新部分页面内容。
1.3.2 AJAX的缺点
1) 没有浏览历史,不能回退
2) 存在跨域问题(同源)
3) SEO 不友好
二、HTTP协议
HTTP全称为hypertext transport protocol 协议【超文本传输协议】,协议详细规定了浏览器和万维网服务器之间互相通信的规则。
重点是格式与参数:
1.请求报文
行: GET/POST /URL HTTP 协议版本
头: Host:值 cookie:值 Content-type:值 User-Agent:值 等等
空行:
体: 如果是GET请求体为空,如果是POST可以不为空
2.响应报文
行: HTTP协议版本 响应状态码 响应状态字符串
头: Content-type:值 Content-length:值 Content-encoding:值 等等
体: HTML语法内容
<html>
<head>
</head>
<body>
<h1>月薪过万</h1>
</body>
</html>
三、AJAX案例准备工作
1.安装express
只需要在vscode => 终端 => 当前目录中 => 输入npm init --yes。
2.创建一个js文件
在当前目录下新建js文件(不一定非要在express安装的根目录),然后在终端=>当前目录下=>输入 node 文件名 就可以启动服务
报错:Error: listen EADDRINUSE: address already in use :::8000
如果端口被占用,找到前一个服务关闭,在终端CTRL+C端口释放,然后重新再到需要开启服务的终端输入node 文件名。
四、发送AJAX请求
1.发送GET请求
点击按钮div:点击按钮发送AJAX请求给服务器,然后把响应体拿过来放到div中。
这部分看不太懂,只是照着敲了一边,后面再回来补。
<button>点击发送请求</button>
<div id="result"></div>
<script>
// 获取button元素
const btn = document.getElementsByTagName('button')[0]
const result = document.getElementById('result')
// 绑定事件
btn.onclick = function () {
//1. 创建对象
const xhr = new XMLHttpRequest()
//2. 初始化 设置请求方法和 url
xhr.open('GET', 'http:127.0.0.1:8000/server?a=100&b=200&c=300')
//3. 发送
xhr.send()
//4. 事件绑定 处理服务端返回的结果
// on 当....时候
// readystate 是 xhr 对象中的属性 , 表示状态 0 1 2 3 4
//其中0-未初始化 1-open调用完毕 2-send调用完毕 3-服务端返回了部分结果 4-服
务端返回了所有结果
//change 改变
xhr.onreadystatechange = function () {
// 判断(服务器返回了所有的结果)
if (xhr.readyState === 4) {
// 判断响应状态码 200 404 403 401 500
// 2xx 成功
if (xhr.status >= 200 && xhr.status < 300) {
//处理结果 行 头 空行 体
//响应
// console.log(xhr.status) //状态码
// console.log(xhr.statusText) //状态字符串
// console.log(xhr.getAllResponseHeaders()) //所有响应头
// console.log(xhr.response) //响应体
// 设置 result 的文本
result.innerHTML = xhr.response
}
}
}
}
</script>
设置url参数:用?隔开,=赋值,&分隔
例如:http://127.0.0.1:8000/server?a=1&b=2&c=3
Server.js 文件:
//1. 引入express
const express = require('express')
//2. 创建应用对象
const app = express()
//3. 创建路由规则
// resquest 是对请求报文的封装
// response 是对响应报文的封装
app.get('/server', (request, response) => {
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
// 设置响应体
response.send('HELLO AJAX')
})
//4. 监听端口启动服务
app.listen(8000, () => {
console.log('服务已经启动,8000 端口监听中...')
})
2.发送POST请求
鼠标经过div发送AJAX请求,然后拿回来响应体放在div中
<div id="result"></div>
传参在send中写,任何类型都可以
可以在xhr.setRequestHeader 设置请求头,不懂可以看下注释
<script>
// 获取元素对象
const result = document.getElementById('result')
// 绑定事件
result.addEventListener('mouseover', function () {
//1. 创建对象
const xhr = new XMLHttpRequest()
//2. 初始化 设置类型与 URL
xhr.open('POST', 'http://127.0.0.1:8000/server')
// 设置请求头:固定写法,第一个参数设置请求体内容类型,第二个参数是参数查询字符串的类型
xhr.setRequestHeader(
'Content-Type',
'application/x-www-form-urlencoded'
)
//3. 发送 在这里传值 任何类型都可
xhr.send('a=100&b=200&c=300')
// xhr.send('a:100&b:200&c:300')
// xhr.send('123456')
//4. 事件绑定
xhr.onreadystatechange = function () {
// 判断
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
// 处理服务端返回的结果
result.innerHTML = xhr.response
}
}
}
})
</script>
server.js
//1. 引入express
const express = require('express')
//2. 创建应用对象
const app = express()
//3. 创建路由规则
// resquest 是对请求报文的封装
// response 是对响应报文的封装
app.post('/server', (request, response) => {
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
// 设置响应体
response.send('HELLO AJAX POST')
})
//4. 监听端口启动服务
app.listen(8000, () => {
console.log('服务已经启动,8000 端口监听中...')
})
3.JSON响应
键盘按下任意按下一个按键,就会向服务端发送请求,服务端返回结果,结果在div中呈现
服务端响应体也可以设置为一个数据发送过去,但是不能直接写,要通过JSON.stringify(数据)把数据转换为JSON字符串
app.get('/json-server', (request, response) => {
//设置响应头
response.setHeader('Access-Control-Allow-Origin', '*');
//响应一个数据
const data = { name: 'atguigu'};
let str = JSON.stringify(data); //对对象进行字符串转换
//设置响应体
response.send(str);
})
(1)手动把JSON字符串转换为js对象
借助JSON.parse(xhr.response)
let data = JSON.parse(xhr.response);
console.log(data); //js对象:{ name: 'ht' }
result.innerHTML = data.name;
(2)自动把JSON字符串转换为js对象
借助 xhr.responseType = 'json';
xhr.responseType = 'json';
......
console.log(xhr.response); //js对象:{ name: 'ht' }
result.innerHTML = xhr.response.name;
nodemon实现保存自动重启服务
终端运行npm install -g nodemon安装nodemon,这样每次保存就会自动重启服务,比较方便(副作用是所有html都无法保存时自动调整格式),使用时还是在当前目录nodemon+文件名 ,如
nodemon server.js(之前是node server.js)
IE缓存问题:
在一些浏览器中(IE),由于缓存机制的存在,ajax 只会发送的第一次请求,剩
余多次请求不会在发送给浏览器而是直接加载缓存中的数据。
解决方式:浏览器的缓存是根据 url 地址来记录的,所以我们只需要修改 url 地址
即可避免缓存问题
xhr.open("get","/testAJAX?t="+Date.now());
app.get('/ie', (request, response) => {
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
// 设置响应体
response.send('HELLO IE - 3')
})
xhr.open('GET', 'http://127.0.0.1:8000/ie?t=' + Date.now()) //获取当前时间戳
2.AJAX请求超时与网络异常处理
服务器写个定时器,3秒后发送响应体
//延时响应
app.get('/delay', (request, response) => {
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
setTimeout(() => {
// 设置响应体
response.send('延时响应')
}, 3000)
})
然后点击按钮发送请求时,可以设置超时xhr.timeout和超时回调xhr.ontimeout,还有网络异常回
调xhr.onerror
const xhr = new XMLHttpRequest()
//超时设置 2s 设置
xhr.timeout = 2000
//超时回调
xhr.ontimeout = function () {
alert('网络异常,请稍后重试!!!')
}
//网络异常回调
xhr.onerror = function () {
alert('您的网络似乎出现了一些问题')
}
浏览器可以手动断网offine
3.AJAX手动取消请求
定时器发送响应体
app.get('/cancel', (request, response) => {
//设置响应头
response.setHeader('Access-Control-Allow-Origin', '*')
//设置响应体
setTimeout(() => {
response.send('HELLO 我请求被取消了,没法发过去了')
}, 3000)
})
写两个按钮
<button>点击发送</button>
<button>点击取消</button>
取消请求,用xhr.abort()方法,abort中文意思是中止
这里边儿有个作用域的问题,解决方法是把xhr定义在外边给个null,然后赋值xhr实例,再调用方法。(重复赋值不要用const,能用const就用const,不能const就let,反正不能用var)
// 获取元素对象
const btns = document.querySelectorAll('button')
let xhr = null
btns[0].onclick = function () {
xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:8000/cancel')
xhr.send() // 不用拿响应体,所有后面不写了
}
//取消请求 abort
btns[1].onclick = function () {
xhr.abort() //先点send再点cancel不会报错,反之报错
// console.log(xhr)
}
4.AJAX请求重复发送问题
服务端还是用的前面的定时器,这里重复请求写个逻辑,如果没处在请求中,就创建新的请求;如果已经请求了,就废掉,再重新创建请求。
// 获取元素对象
const btns = document.querySelectorAll('button')
let xhr = null
// 标识变量
let isSending = false // 是否正在发送AJAX请求
btns[0].onclick = function () {
// 判断标识符变量
if (isSending) xhr.abort() // 如果正在发生,则取消该请求,创建一个新的请求
xhr = new XMLHttpRequest()
// 修改 标识变量的值
isSending = true
xhr.open('GET', 'http://127.0.0.1:8000/cancel')
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
// 修改标识变量 有可能请求失败,所以这里不用再做判断,只要拿到结果,就算请求完成
isSending = false // 拿到服务器的全部结果后,置为false
}
}
}
五、AJAX 请求状态
xhr.readyState 可以用来查看请求当前的状态
XMLHttpRequest.readyState - Web API 接口参考 | MDN
0: 表示 XMLHttpRequest 实例已经生成,但是 open()方法还没有被调用。
1: 表示 send()方法还没有被调用,仍然可以使用 setRequestHeader(),设定 HTTP请求的头信息。
2: 表示 send()方法已经执行,并且头信息和状态码已经收到。
3: 表示正在接收服务器传来的 body 部分的数据。
4: 表示服务器数据已经完全接收,或者本次接收已经失败了