1. AJAX 简介
AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:==无刷新获取数据==。AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
2. AJAX特点
2.1AJAX 的优点
- 可以无需刷新页面而与服务器端进行通信。
- 允许你根据用户事件来更新部分页面内容。
2.2 AJAX 的缺点
- 没有浏览历史,不能回退
- 存在跨域问题(同源)
- SEO 不友
3.使用
3.1 XMLHttpRequest
有关Ajax的所有操作都是通过XMLHttpRequest
来操作的。
3.2 服务端的准备
在使用Ajax之前,因为需要对服务端发送请求,因此这里使用express
框架,创建server.js
文件搭建一个服务器。由于Ajax默认是服从同源策略,因此在服务器中设置Access-Control-Allow-Origin
响应头在解决跨域问题(CORS跨域)。
// server.js
const express = require('express')
// 创建应用对象
const app = express()
// 创建路由规则
app.get('/index', (request, response) => {
// 设置允许跨域的响应头
response.setHeader('Access-Control-Allow-Origin', '*')
// 设置响应体
response.send('hello ajax')
})
app.post('/index', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*')
response.send('post ajax')
})
// 监听端口,启动服务
app.listen(8282, () => {
console.log('服务器启动,8000端口监听中...');
})
复制代码
在测试过程中,要保证服务端处于开启状态,开启命令:node server.js
3.3 ajax发送get请求
准备一个html
文档,点击按钮向接口http://127.0.0.1:8282/index
发送请求,请求的数据显示在div
中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ajax get请求</title>
<style>
.result{
border: 1px solid black;
width: 250px;
height: 150px;
}
</style>
</head>
<body>
<button>发送请求</button>
<br>
<br>
<div class="result"></div>
<script>
let button = document.getElementsByTagName('button')[0]
let divObj = document.getElementsByClassName('result')[0]
button.addEventListener('click', function(){
// 创建对象
const xhr = new XMLHttpRequest()
// 设置请求方法和url
xhr.open('GET', 'http://127.0.0.1:8282/index')
// 发送请求
xhr.send()
// 处理服务端返回的结果
xhr.onreadystatechange = function() {
/*
readyState属性值:
0 - 对象未初始化
1 - open方法执行
2 - send方法执行
3 - 服务端返回部分结果
4 - 服务端返回全部结果
*/
if(xhr.readyState === 4) {
// 判断响应状态码 2xx成功
if(xhr.status >= 200 && xhr.status < 300) {
// 响应行
// console.log(xhr.status)
// console.log(xhr.statusText) // 状态描述
// // 响应头
// console.log(xhr.getAllResponseHeaders())
// // 响应体
// console.log(xhr.response)
divObj.innerHTML = xhr.response
}
}
}
})
</script>
</body>
</html>
复制代码
结果:
若需要在发送get请求时携带参数,则url应写为:
xhr.open('GET', 'http://127.0.0.1:8282/index?a=100&b=200&c=300')
复制代码
3.4 发送post请求
将原来代码中xhr.open()
第一个参数右GET
改为POST
:
xhr.open('POST','http://127.0.0.1:8282/index')
复制代码
使用post方法发送请求体时,要将请求体内容放在send
方法中,格式不固定,只要服务端能够处理即可:
// 形式一
xhr.send('a=100&b=200&c=300')
// 形式二
xhr.send('a:100&b:200&c:300')
// ...
复制代码
3.5 设置请求头信息
// Content-Type 请求体类型
// application/x-www-form-urlencoded 查询字符串类型
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
复制代码
自定义请求头
xhr.setRequestHeader('Name', 'Alice')
复制代码
此时服务端需要设置Access-Control-Allow-Headers
字段,表示可以接收处理的请求头,否则会报错:
app.post('/index', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*')
response.setHeader('Access-Control-Allow-Headers', '*')
response.send('post ajax')
})
复制代码
一般可以在请求头中存放服务端要校验的信息。
3.6 服务端响应 json数据时
服务端若需要将json对象的数据返回给客户端,需要将其转为JSON字符串再发送,server.js
添加代码如下:
// all()表示可以匹配所有请求的方法
app.all('/json-data', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*')
response.setHeader('Access-Control-Allow-Headers', '*')
// 响应json数据,需要将json对象转为字符串格式
const data = {
'name': 'Alice',
'age': 34
}
response.send(JSON.stringify(data))
})
复制代码
客户端处理结果时,需要将json字符串转为json对象:
button.addEventListener('click',function() {
let xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:8282/json-data')
xhr.send()
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
// 将服务端返回的json数据转为json对象
let data = JSON.parse(xhr.response)
console.log(data)
}
}
}
})
复制代码
控制台:
或者可以直接在xhr
对象上设置响应体类型为json
,就不用执行转换步骤:
button.addEventListener('click',function() {
let xhr = new XMLHttpRequest()
xhr.responseType = 'json'
xhr.open('GET', 'http://127.0.0.1:8282/json-data')
xhr.send()
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
let data = xhr.response
console.log(data)
}
}
}
})
复制代码
控制台:
3.7 解决IE缓存问题
在IE浏览器中,发送Ajax请求回来的数据会被缓存,导致在某些时效性比较强的场景下会得到错误的数据。因此需要在url
中携带一个表示时间戳的参数,使得IE浏览器认为每次都在发送不同的请求:
xhr.open('get', 'http://127.0.0.1:8282/json-data?t='+Date.now())
复制代码
3.8 请求超时和网络异常处理
可以在xhr
对象上设置超时时间,若在这个时间之内没有获取到响应结果,则会自动取消。例如,在服务端设置3秒后返回结果:
// 延迟响应
app.get('/delay', (request, response) => {
response.setHeader('Access-Control-Allow-Origin', '*')
setTimeout(() => {
response.send('延迟响应')
}, 3000)
})
复制代码
客户端设置超时时间为2s
<script>
let button = document.getElementsByTagName('button')[0]
let divObj = document.getElementsByTagName('div')[0]
button.addEventListener('click', function() {
let xhr = new XMLHttpRequest()
// 设置超时2s取消请求
xhr.timeout = 2000
// 超时回调
xhr.ontimeout = function() {
alert('网络较慢,请稍后重试!')
}
xhr.open('GET', 'http://127.0.0.1:8282/delay')
xhr.send()
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
divObj.innerHTML = xhr.response
}
}
}
})
</script>
复制代码
控制台:
也可以设置网络异常时的回调:
xhr.onerror = function() {
alert('网络异常!')
}
复制代码
在浏览器中,将网络状态设为offline
,模拟没有网络的情况
3.9 取消请求
xhr
对象上的abort()
可以用于取消请求:
xhr.abort()
复制代码
3.10 重复发送请求问题
当我们多次点击按钮发送请求时,会对服务器造成一定压力,且多次请求的操作并不是必要的,解决这个重复请求问题,需要当再次发送请求时,把上一次没完成的请求取消掉。
<body>
<button>发送请求</button>
<script>
let button = document.getElementsByTagName('button')[0]
// 是否正在处理ajax请求的标识
let isSending = false
let xhr
button.addEventListener('click', function() {
// 如果上一次请求还在,取消,重新发起请求
if(isSending) {
xhr.abort()
}
xhr = new XMLHttpRequest()
isSending = true
xhr.open('GET', 'http://127.0.0.1:8282/delay')
xhr.send()
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
// 请求处理完,无论状态码是什么,都是为false
isSending = false
}
}
})
</script>
</body>
复制代码