Ajax基础
1. 传统网站中存在的问题
- 网速慢的情况下, 页面加载时间长, 用户只能等待
- 表单提交后, 如果一项内容不合格, 需要重新填写所有表单内容
- 页面跳转, 重新加载页面, 造成资源浪费, 增加用户等待时间
2. Ajax概述
它是浏览器提供的一套方法, 可以实现页面无刷新更新数据, 提高用户浏览网站应用体验
3. Ajax的应用场景
- 页面上拉加载更多数据
- 列表数据无刷新分页
- 表单项离开焦点数据验证
- 搜索框提示文字下拉列表
4. Ajax 的运行环境
Ajax技术需要运行在网站环境中才能生效, 可以使用Node创建服务器作为网站服务器。
Ajax 运行原理及实现
1. Ajax 运行原理
Ajax相当于浏览器发送请求与接收响应的代理人, 以实现在不影响用户浏览页面的情况下, 局部更新页面数据, 从而提高用户体验。
2. Ajax 的实现步骤
- 创建 Ajax 对象
var xhr = new XMLHttpRequest();
- 告诉Ajax请求地址以及请求方式
xhr.open('get', 'http://www.example.com')
- 发送请求
xhr.send()
- 获取服务器端与客户端的响应数据
xhr.onload = function () {
console.log(xhr.responseText)
}
服务端代码
const express = require('express')
const path = require('path')
const app = express()
app.use(express.static(path.join(__dirname, 'public')))
app.get('/first', (req, res) => {
res.send('hello ajax')
})
app.listen(3000, () => console.log('服务器启动成功'))
ajax代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1. 创建ajax对象
const xhr = new XMLHttpRequest()
// 2. 告诉ajax对象要向哪发送请求, 以什么方式发送请求
// 1) 请求方式 2)请求地址
xhr.open('get', 'http://localhost:3000/first')
// 3. 发送请求
xhr.send()
// 4. 获取服务器端响应到客户端的数据
xhr.onload = function () {
console.log(xhr.responseText)
}
</script>
</body>
</html>
运行结果
3. 服务器端响应的数据格式
在真实的项目中, 服务器端大多数情况下会以JSON对象作为响应数据的格式。当客户端拿到响应数据时,要将JSON数据和HTML字符串进行拼接,然后将拼接的结果展示在页面中。
- ajax代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/responseData')
xhr.send()
xhr.onload = function () {
console.log(xhr.responseText)
console.log(typeof xhr.responseText)
}
</script>
</body>
</html>
- 服务端代码
const express = require('express')
const path = require('path')
const app = express()
app.use(express.static(path.join(__dirname, 'public')))
app.get('/first', (req, res) => {
res.send('hello ajax')
})
app.get('/responseData', (req, res) => {
res.send({"name": "zhangsan"})
})
app.listen(3000, () => console.log('服务器启动成功'))
- 运行结果
在 http 请求与响应的过程中, 无论是请求参数还是响应内容, 如果是对象对象类型, 最终都会被转换为对象字符串进行传输。
JSON.psrse() // 将json字符串转换为json对象
- ajax代码
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/responseData')
xhr.send()
xhr.onload = function () {
// 将JSON字符串转换为JSON对象
let responseText = JSON.parse(xhr.responseText)
console.log(responseText)
var str = '<h2>' + responseText.name + '</h2>'
document.body.innerHTML = str
}
- 服务端代码和上面的一样
- 运行结果
4. 请求参数传递
4.1. get请求参数
- ajax代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>
<input type="text" id="username">
</p>
<p>
<input type="text" id="age">
</p>
<p>
<input type="button" value="提交" id="btn">
</p>
<script>
var btn = document.getElementById('btn')
var username = document.getElementById('username')
var age = document.getElementById('age')
btn.onclick = function () {
// 创建ajax对象
const xhr = new XMLHttpRequest()
// 获取用户在文本框中的数据值
var nameValue = username.value
var ageValue = age.value
// 拼接请求参数
var params = 'username=' + nameValue + '&age=' + ageValue
// 配置ajax对象
xhr.open('get', 'http://localhost:3000/get?' + params)
// 发送请求
xhr.send()
// 获取服务器端的响应数据
xhr.onload = function () {
console.log(xhr.responseText)
}
}
</script>
</body>
</html>
- js代码
const express = require('express')
const path = require('path')
const app = express()
app.use(express.static(path.join(__dirname, 'public')))
app.get('/first', (req, res) => {
res.send('hello ajax')
})
app.get('/responseData', (req, res) => {
res.send({"name": "zhangsan"})
})
app.get('/get', (req, res) => {
res.send(req.query)
})
app.listen(3000, () => console.log('服务器启动成功'))
4.2. post请求
- ajax代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>
<input type="text" id="username">
</p>
<p>
<input type="text" id="age">
</p>
<p>
<input type="button" value="提交" id="btn">
</p>
<script>
var btn = document.getElementById('btn')
var username = document.getElementById('username')
var age = document.getElementById('age')
btn.onclick = function () {
// 创建ajax对象
const xhr = new XMLHttpRequest()
// 获取用户在文本框中的数据值
var nameValue = username.value
var ageValue = age.value
// 拼接请求参数
var params = 'username=' + nameValue + '&age=' + ageValue
// 配置ajax对象
xhr.open('post', 'http://localhost:3000/post')
// 设置请求参数格式的类型, post请求必须设置
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 发送请求
xhr.send(params)
// 获取服务器端的响应数据
xhr.onload = function () {
console.log(xhr.responseText)
}
}
</script>
</body>
</html>
- 服务端代码
const express = require('express')
const bodyParser = require('body-parser')
const path = require('path')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(express.static(path.join(__dirname, 'public')))
app.get('/first', (req, res) => {
res.send('hello ajax')
})
app.get('/responseData', (req, res) => {
res.send({"name": "zhangsan"})
})
app.get('/get', (req, res) => {
res.send(req.query)
})
app.post('/post', (req, res) => {
res.send(req.body)
})
app.listen(3000, () => console.log('服务器启动成功'))
- 运行结果
4.3. 请求报文
- 在HTTP请求和响应过程中传递的数据块就叫
报文
, 包括要传递的数据和一些附加信息, 这些数据和信息要遵守规定好的格式
5.请求参数的格式
- application/x-www-form-urlencoded
name=zhangsan&age=20
- application/json
{ name: ‘zhangsan’, age: ‘20’ }
- 在请求头中指定 Content-Type 属性的值是 application/json, 告诉服务器端挡墙请求参数的格式是json
JSON.stringify() // 将json对象转换为json字符串
- ajax代码
// 创建ajax对象
const xhr = new XMLHttpRequest()
// 配置ajax对象
xhr.open('post', 'http://localhost:3000/json')
xhr.setRequestHeader('Content-Type', 'application/json')
// 发送请求
xhr.send(JSON.stringify({name: 'lisi', age: 50}))
// 获取服务器端的响应数据
xhr.onload = function () {
console.log(xhr.responseText)
}
- 服务端代码
const express = require('express')
const bodyParser = require('body-parser')
const path = require('path')
const app = express()
app.use(bodyParser.json())
app.use(express.static(path.join(__dirname, 'public')))
app.post('/json', (req, res) => {
res.send(req.body)
})
app.listen(3000, () => console.log('服务器启动成功'))
注意: get请求是不能提交json对象数据格式的, 传统网站的表单提交验配师不支持json对象数据格式的
6. 获取服务器端的响应
6.1 Ajax状态码
-
在创建ajax对象, 配置ajax对象, 发送请求, 以及接受完服务器端响应数据, 这个过程中的每一个步骤都会对应一个数值, 这个数值就是ajax状态码
0: 请求未初始化(还没有调用open())
1: 请求已经建立, 但是还没有发送(还没有调用send())
2: 请求已经发送
3: 请求正在处理中, 通常响应中已经有部分数据可以用了
4: 响应已经完成, 可以获取并使用服务器的响应了
xhr.readyState // 获取ajax状态码
-
onreadystatechange 事件
当ajax状态码发生变化时将自动触发该事件。
在事件处理函数中可以获取 Ajax状态码并对其进行判断, 当状态码为 4 时就可以通过xhr.responseText
获取服务器端响应的数据了 -
ajax代码
var xhr = new XMLHttpRequest()
// 0 已经创建了ajax对象 但是还没有对ajax对象进行配置
console.log(xhr.readyState)
xhr.open('get', 'http://localhost:3000/readystate')
// 1 已经对ajax对象进行配置, 但是会还没有发送请求
console.log(xhr.readyState)
// 当ajax状态码发生变化的时候触发
xhr.onreadystatechange = function () {
// 2 请求已经发送了
// 3 已经接收到服务器端的部分数据了
// 4 服务器端的响应数据已经接受完成
console.log(xhr.readyState)
// 对ajax状态码进行判断 如果状态码的值为 4 就代表数据已经接受完成了
if (xhr.readyState === 4) {
console.log(xhr.responseText)
}
}
xhr.send()
- 服务器端代码
const express = require('express')
const bodyParser = require('body-parser')
const path = require('path')
const app = express()
app.use(bodyParser.json())
app.use(express.static(path.join(__dirname, 'public')))
app.get('/readystate', (req, res) => {
res.send('ok')
})
app.listen(3000, () => console.log('服务器启动成功'))
6.2 两种获取服务器端响应方式的区别
7. Ajax 错误处理
- 网络通畅, 服务器端能接收到请求, 服务器端返回的结果不是预期结果
可以判断服务器端返回的状态码, 分别进行处理,
xhr.status
获取http状态码
- ajax代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">发送Ajax请求</button>
<script>
var btn = document.getElementById('btn')
btn.onclick = function () {
var xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/error')
xhr.send()
xhr.onload = function () {
// xhr.status 获取http状态码
console.log(xhr.responseText)
if (xhr.status === 400) {
alert('请求出错')
}
}
}
</script>
</body>
</html>
- 服务器端代码
const express = require('express')
const bodyParser = require('body-parser')
const path = require('path')
const app = express()
app.use(bodyParser.json())
app.use(express.static(path.join(__dirname, 'public')))
app.post('/post', (req, res) => {
res.send(req.body)
app.get('/error', (req, res) => {
res.status(400).send('not ok')
})
app.listen(3000, () => console.log('服务器启动成功'))
-
网络通畅, 服务器端没有接受到请求, 返回 404 状态码
检查请求地址是否错误
-
网络畅通, 服务器端能接受到请求, 服务器端返回 500 状态码
服务器端错误
-
网络中断, 请求无法发送到服务器端
会触发xhr对象下面的error事件, 在onerror事件处理函数中对错误进行处理
<button id="btn">发送Ajax请求</button>
<script>
var btn = document.getElementById('btn')
btn.onclick = function () {
var xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/error')
xhr.send()
xhr.onload = function () {
// xhr.status 获取http状态码
console.log(xhr.responseText)
if (xhr.status === 400) {
alert('请求出错')
}
}
// 当网络中断时会触发onerror事件
xhr.onerror = function () {
alert('网络中断, 无法发送ajax请求')
}
}
</script>
8. 低版本 IE 浏览器的缓存问题
问题
: 在低版本的IE浏览器中, Ajax请求有严重的缓存问题, 即在请求地址不发生变化的情况下, 只有第一次请求会真正发送到服务器端, 后续的请求都会从浏览器的缓存中获取结果, 即使服务器端的数据更新了, 客户端依然拿到的是缓存中的旧数据。
- ajax 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">发送Ajax请求</button>
<script>
var btn = document.getElementById('btn')
btn.onclick = function () {
var xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/cache')
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText)
}
}
// 当网络中断时会触发onerror事件
xhr.onerror = function () {
alert('网络中断, 无法发送ajax请求')
}
}
</script>
</body>
</html>
- 服务端代码
const express = require('express')
const bodyParser = require('body-parser')
const path = require('path')
const fs = require('fs')
const app = express()
app.use(bodyParser.json())
app.use(express.static(path.join(__dirname, 'public')))
app.get('/cache', (req, res) => {
fs.readFile('./test.txt', (err, result) => {
res.send(result)
})
})
app.listen(3000, () => console.log('服务器启动成功'))
- test.txt文件
hello
运行结果(这里用的是IE 8)
- 更改test.txt文件里面的内容为
hello 123
到浏览器中运行, 结果还是和上面的一样
解决方案
在请求地址的后面加请求参数, 保证每一次请求中的请求参数的值不同
xhr.open('get', 'http://localhost:3000/cache?t=' + Math.random())
运行结果(浏览器是IE 8)