文章目录
原生Ajax
1 AJAX 简介
AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
比如:注册页面,填用户名,下面可能就会提示用户名重复需要更换,这个时候就是Ajax向服务器发送了请求。
比如:淘宝页面,鼠标移到哪个小图标,就会显示相应的信息,这个就是一种懒加载,按需求加载,Ajax向服务器发请求,返回结果
同步:一定要等任务执行完了,得到结果,才执行下一个任务。
异步:不等任务执行完,直接执行下一个任务。
2 XML 简介
XML 可扩展标记语言。
XML 被设计用来传输和存储数据。
eg:一个数据,前端需要,可以通过网络以XML形式把结果给服务端,服务端就可以使用
XML 和 HTML 类似,不同的是 HTML 中都是预定义标签(a,p等标签),而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据
HTML是在网页端呈现数据的
服务器端给客户端浏览器返回的结果就是XML格式字符串,前端js接收到结果,对内容进行一个解析,把数据提取出来,对数据做一个处理
eg: 比如说我有一个学生数据
name = "孙悟空" ; age = 18 ; gender = "男" ;
用 XML 表示:
<student>
<name>孙悟空</name>
<age>18</age>
<gender>男</gender>
</student>
现在已经被 JSON 取代了。
用 JSON 表示:
{"name":"孙悟空","age":18,"gender":"男"}
JSON相对于XML更简洁,数据转换更加容易
之后使用都是用JSON,不用XML
3 AJAX 的特点
3.1 AJAX 的优点
- 可以无需刷新页面而与服务器端进行通信。
- 允许你根据用户事件(鼠标事件,键盘事件,文档事件等)来更新部分页面内容。
3.2 AJAX 的缺点
- 没有浏览历史,不能回退
- 存在跨域问题(同源)
跨域:在一个服务向另外一个服务发送请求 eg a.com—>b.com发请求,默认是不可以,但是可以解决
- SEO 不友好
SEO Search Engine Optimization 搜索引擎优化 网页内容,爬虫爬不到
4 HTTP 协议
HTTP(Hyper Text Transfer Protocol,HTTP)协议【超文本传输协议】,协议详细的规定了浏览器和万维网服务器之间相互通信的规则
浏览网页绝大多数的数据交换都是用的HTTP协议
协议就是约定,规则,两块内容:请求,响应
请求报文
向服务器发送请求,四个部分,请求行、头、空行、体
重点是格式于参数
行 GET /s?ie=utf-8 HTTP/1.1
头 Host: atguigu.com
Cookie: name=guigu
Contenty-type: application/x-www-form-urlencoded
User-Agent: chrome 83
空行
体 username=admin&password=admin
行 包括三个部分:
1 GET 请求类型 GET POST
2 /s?ie=utf-8 url路径 对应查询字符串,eg: 搜索谷粒学院/com后面会显示很多参数,就放在这个地方
3 HTTP/1.1 HTTP版本1.1
空行是固定的,必须有
体:可以有内容,也可以没有内容。 如果是GET请求,请求体是空的,如果是POST 请求体可以不为空
响应报文
行 HTTP/1.1 200 OK
头 Content-Type: text/html;charset=utf-8
Content-length: 2048
Content-encoding: gzip
空行
体 <html>
<head>
</head>
<body>
<h1>尚硅谷</h1>
</body>
</html>
行 HTTP/1.1(协议版本) 200(响应状态码,eg 404,403,401) OK(响应状态字符串)
体 主要返回的结果 html内容放在响应体
Chrome网络控制台查看通信报文
eg 登录网站 processon.com/login
点击登录,控制台就会发送请求
5 node.js的安装
node.js:一个应用程序,可以解析js代码,然后通过js代码对计算机资源进行一个操作
整个ajax应用,需要一个服务端,所以我们安装node.js
网站下载,直接傻瓜式安装即可
检测是否成功安装:
win+R—>cmd—>输入命令:node -v —>出现类似v16.14.0 说明安装成功
6 express框架介绍和基本使用
6.1 express简介
Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。
使用 Express 可以快速地搭建一个完整功能的网站。
Express 框架核心特性:
- 可以设置中间件来响应 HTTP 请求。
- 定义了路由表用于执行不同的 HTTP 请求动作。
- 可以通过向模板传递参数来动态渲染 HTML 页面。
因为ajax需要给服务端发送请求,需要一个服务端,所以我们选express框架
6.2 安装express框架
首先打开终端(在文件最外层打开)—> 输入 npm init --yes回车 做一个初始化—>安装 输入 npm i express
安装之后会出现三个文件
6.3 express基本使用
express基本使用.js
// 1 引入express
const { request } = require('express');
const express = require('express');
// 2 创建应用对象
const app = express();
// 3 创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
app.get('/', (request, response)=>{
// 设置响应
response.send('HELLO EXPRESS');
});
// 4 监听端口启动服务
app.listen(8000, ()=>{
console.log("服务已经启动, 8000端口监听中...");
})
启动服务
(1) 用node 命令去执行这个脚本
右键express基本使用.js上一层文件(express框架)—> 终端打开 —> 输入命令 node express基本使用.js
端口监听中
(2) 打开浏览器 输入网址: 127.0.0.1:8000
发送
响应
7 AJAX请求发送前的准备
1 前端页面的准备 2 服务端代码的准备
7.1 前端页面
需求:点击按钮向服务端发送请求,把服务端返回的响应体结果在div做出呈现
1-GET.html
<!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>AJAX GET 请求</title>
<style>
#result {
width: 200px;
height: 100px;
border: solid 1px #90b;
}
</style>
</head>
<body>
<!-- 需求:点击按钮向服务端发送请求,把服务端返回的响应体结果在div做出呈现 -->
<button>点击发送请求</button>
<div id="result"></div>
</body>
</html>
7.2 服务端代码
把刚刚写的express基本使用.js代码 复制粘贴过来,然后稍作修改
/ —> /server 效果:
客户端浏览器向服务器发送请求时,如果url路径是请求行第二段内容 路径是/server,这时就会执行回调函数((request, response)=>{})里面的代码,并且由response做出响应
// 1 引入express
const express = require('express');
// 2 创建应用对象
const app = express();
// 3 创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
app.get('/server', (request, response)=>{
// 设置响应头 设置允许跨域
// 头的名字(Access-Control-Allow-Origin) 头的值(*)
response.setHeader('Access-Control-Allow-Origin','*')
// 设置响应体
response.send('HELLO AJAX');
});
// 4 监听端口启动服务
app.listen(8000, ()=>{
console.log("服务已经启动, 8000端口监听中...");
})
启动服务
右键上一级文件打开终端 —> node server.js
此时会报错,需要关闭之前的端口
解决方法:ctrl+c释放之前的端口。(其他解决方法:直接关闭软件重新打开就行,再去终端输入命令)
端口号启动成功
去测试一下 打开浏览器 输入 127.0.0.1:8000/server
8 AJAX请求的基本操作
还是以上面的案例为支撑
需求:点击按钮向服务端发送请求,把服务端返回的响应体结果在div做出呈现
8.1 核心对象
XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的。
8.2 使用步骤
- 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
- 设置请求信息
xhr.open(method, url);
//可以设置请求头,一般不设置
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
- 发送请求
xhr.send(body) //get 请求不传 body 参数,只有 post 请求使用
- 接收响应
//xhr.responseXML 接收 xml 格式的响应数据
//xhr.responseText 接收文本格式的响应数据
xhr.onreadystatechange = function (){
if(xhr.readyState == 4 && xhr.status == 200){
var text = xhr.responseText;
console.log(text);
}
}
1-GET.HTML
<!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>AJAX GET 请求</title>
<style>
#result {
width: 200px;
height: 100px;
border: solid 1px #90b;
}
</style>
</head>
<body>
<!-- 需求:点击按钮向服务端发送请求,把服务端返回的响应体结果在div做出呈现 -->
<button>点击发送请求</button>
<div id="result"></div>
<script>
// 获取button元素
const btn = document.getElementsByTagName('button')[0];
const result = document.getElementById("result");
// 绑定事件
btn.onclick = function() {
// 1 创建对象
// xhr XMLHttpRequest缩写,看到xhr要想到时Ajax
const xhr = new XMLHttpRequest();
// 2 初始化 设置请求方法和url
xhr.open('GET', 'http://127.0.0.1:8000/server');
// 3 发送
xhr.send();
// 4 事件绑定 处理服务端返回的结果
// on when 当...时候
// readystate 是xhr对象中的属性 表示状态 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) {
// 处理结果 行 头 空行 体
// 1 响应行
// console.log(xhr.status); // 状态码
// console.log(xhr.statusText); // 状态字符串
// console.log(xhr.getAllResponseHeaders()); // 所有响应头
// console.log(xhr.response); // 响应体
// // 拿到响应结果之后需要在div做一个呈现
// 设置 result 的文本
// 当发送请求就会返回一个结果,在div 并没有刷新,页面就直接显示了文本
result.innerHTML = xhr.response;
}
}
}
}
</script>
</body>
</html>
效果:(当发送请求就会返回一个结果,在div 并没有刷新,页面就直接显示了文本)
`
9 Ajax设置get请求参数(url参数)
在url后面去缀参数
写法:
用问号分割 + 参数名字和值 再用and符分割,& 如果有多个参数
eg:
xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');
效果:
10 Ajax发送post请求
需求:鼠标放在div盒子上面,然后向服务端发送请问POST请求,结果回来以后,把响应体结果在div中做一个呈现
2-POST.html
<!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>AJAX POST 请求</title>
<style>
#result {
width: 200px;
height: 100px;
border: solid 1px #903;
}
</style>
</head>
<body>
<div id="result"></div>
<script>
// 获取元素对象
const result = document.getElementById("result");
// 绑定事件
result.addEventListener("mouseover", function() {
// 1 创建对象
const xhr = new XMLHttpRequest();
// 2 初始化 设置类型与 url
// 还是给8000端口发请求
xhr.open('POST', 'http:/127.0.0.1:8000/server');
// 3 发送
xhr.send();
// 4 事件绑定
xhr.onreadystatechange = function() {
// 判断
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
// 处理服务端返回的结果
result.innerHTML = shr.response;
}
}
}
})
</script>
</body>
</html>
上面代码运行后会报错,原因是server.js里面目前只有get请求相关代码,而我们现在需要一个post的,可以添加代码到server.js
app.post('/server', (request, response)=>{
// 设置响应头 设置允许跨域
// 头的名字(Access-Control-Allow-Origin) 头的值(*)
response.setHeader('Access-Control-Allow-Origin','*')
// 设置响应体
response.send('HELLO AJAX POST');
});
js代码在改完之后,一定要重新启动服务。
打开终端,停掉之前的服务,再启动服务
10.1 post请求设置请求体(参数)
eg
xhr.send('a=100&b=200&c=300');
也可以写成别的 写法(见代码部分)
11 Ajax设置请求头信息
// 设置请求头
// Content-Type预定义
xhr.setRequestHeader('Content-Type','applicatix-www-form-urlencoded');
// name自定义 自定义浏览器会有安全机制 会报错,需要在面加一个特殊的响应头.这个一般都是后端人员做
xhr.setRequestHeader('name', 'atguigtu');
// all 可以接收任意类型的请求
app.all('/server', (request, response)=>{
// 设置响应头 设置允许跨域
// 头的名字(Access-Control-Allow-Origin) 头的值(*)
response.setHeader('Access-Control-Allow-Origin','*');
// 响应头
response.setHeader('Access-Control-Allow-Headers','*');
// 设置响应体
response.send('HELLO AJAX POST');
});
12 服务端响应JSON数据
实际工作,我们向服务端发送请求,服务端返回结果,绝大多数都是一个JSON格式的数据
需求:键盘按下,向服务端发送请求,服务端返回结果呈现在div中
eg. 3-POST.html
<!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>JSON响应</title>
<style>
#result {
width: 200px;
height: 100px;
border: solid 1px #89b;
}
</style>
</head>
<body>
<div id="result"></div>
<script>
// 绑定键盘按下事件
window.onkeydown = function() {
// 发送请求
const xhr = new XMLHttpRequest();
// 设置响应体数据的类型
xhr.responseType = 'json';
// 初始化
xhr.open('GET', 'http://127.0.0.1:8000/json-server');
// 发送
xhr.send();
// 事件绑定
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
// console.log(xhr.response);
// result.innerHTML = xhr.response;
// 手动对数据转换
// let data = JSON.parse(xhr.response);
// console.log(data);
// result.innerHTML = data.name;
// 自动转换
console.log(xhr.response);
result.innerHTML = xhr.response.name;
}
}
}
}
</script>
</body>
</html>
app.all('/json-server', (request, response)=>{
// 设置响应头 设置允许跨域
// 头的名字(Access-Control-Allow-Origin) 头的值(*)
response.setHeader('Access-Control-Allow-Origin','*');
// 响应头
response.setHeader('Access-Control-Allow-Headers','*');
// 响应一个数据 对象
const data = {
name: 'atguigu'
}
// 将对象惊醒字符串转换
let str = JSON.stringify(data)
// 设置响应体
// 这个send里面只能接收字符串和...
response.send(str);
});
13 nodemon自动重启工具安装
nodemon:帮助我们自动重启服务、应用
由于之前更改server.js每次我们都会重启服务,很麻烦,所以我们就使用这个工具
安装:(前提是安装好nodejs)
1 首先关闭服务
2 打开命令行,输入 npm install -g nodemon
等待下载好
3 重新启动服务 输入nodemon server.js
(与之前指令不同)
4 现在,当直接修改server.js里面代码再保存,终端就会接着自动启动服务,显示8000端口监听中
14 解决 IE 缓存问题
问题:在一些浏览器中(IE),由于缓存机制的存在,ajax 只会发送的第一次请求,剩余多次请求不会在发送给浏览器而是直接加载缓存中的数据。
IE浏览器会对Ajax的请求结果去做一个缓存,把结果缓存起来,这样就会导致下一次发送请求时走的是本地缓存,而不是服务器返回的最新数据,这样对于时效性强的擦汗场景,Ajax缓存会影响结果,不能正常显示,所以我们需要去解决这个问题。
解决方式:浏览器的缓存是根据 url 地址来记录的,所以我们只需要修改 url 地址
即可避免缓存问题
xhr.open("get","/testAJAX?t="+Date.now());
这些问题工具都会给我们加好,我们只需要知道这个IE缓存问题
eg. 4-IE缓存问题.html
<!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>IE缓存问题</title>
<style>
#result {
width: 200px;
height: 100px;
border: solid 1px #258;
}
</style>
</head>
<body>
<button>点击发送请求</button>
<div id="result"></div>
<script>
const btn = document.getElementsByTagName('button')[0];
const result = document.querySelector("#result");
btn.addEventListener('click', function() {
// 向服务端发送请求
const xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000/ie?t='+Date.now());
xhr.send();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
}
}
}
})
</script>
</body>
</html>
// 针对 IE 缓存
app.get('/ie', (request, response)=>{
// 设置响应头 设置允许跨域
// 头的名字(Access-Control-Allow-Origin) 头的值(*)
response.setHeader('Access-Control-Allow-Origin','*')
// 设置响应体
response.send('HELLO IE -2');
});
15 Ajax请求超时和网络异常处理
需求:点击按钮发送请求给服务端,服务端返回结果在div中呈现。
如果2s后没有返回结果,就提示网络超时
eg 5-超时与网络异常.html
<!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>请求超时与网络异常</title>
<style>
#result {
width: 200px;
height: 100px;
border: solid 1px #90b;
}
</style>
</head>
<body>
<button>点击发送请求</button>
<div id="result"></div>
<script>
const btn = document.getElementsByTagName('button')[0];
const result = document.querySelector("#result");
btn.addEventListener('click', function() {
// 向服务端发送请求
const xhr = new XMLHttpRequest();
// 超时设置 2s 设置 (2s内没有结果,请求就取消)
xhr.timeout = 2000;
// 超时回调
xhr.ontimeout = function() {
alert("网络异常,请稍后重试!!");
}
// 网络异常回调
xhr.onerror = function() {
alert("你的网络似乎有问题!!")
}
xhr.open('GET','http://127.0.0.1:8000/delay');
xhr.send();
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
result.innerHTML = xhr.response;
}
}
}
})
</script>
</body>
</html>
// 延时响应
app.get('/delay', (request, response)=>{
// 设置响应头 设置允许跨域
// 头的名字(Access-Control-Allow-Origin) 头的值(*)
response.setHeader('Access-Control-Allow-Origin','*')
setTimeout(() => {
// 设置响应体
response.send('延时响应');
}, 3000);
});
其中:无网络可以这样设置
15 Ajax取消请求
在结果还没有返回之前,通过代码手动取消请求
eg. 6-取消请求.html
<!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>取消请求</title>
</head>
<body>
<button>点击发送</button>
<button>点击取消</button>
<script>
const btns = document.querySelectorAll('button');
let x = null;
// x 不能用 const 使用会报错
btns[0].onclick = function() {
x = new XMLHttpRequest();
x.open("GET",'http://127.0.0.1:8000/delay');
x.send();
}
// abort
btns[1].onclick = function() {
x.abort();
}
</script>
</body>
</html>
15 Ajax请求重复发送问题
当服务器响应很慢时,用户一直点击发送请求,这时服务器压力会很大,会接收到很多相同请求。我们要解决这个问题,当用户发送相同请求时,我们就去取消这个请求
eg. 7-重复请求问题.html
<!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>重复请求问题</title>
</head>
<body>
<button>点击发送</button>
<script>
const btns = document.querySelectorAll('button');
let x = null;
// 标识变量
let isSending = false; // 是否正在发送AJAX请求
btns[0].onclick = function() {
// 判断元素对象
if(isSending) x.abort(); // 如果正在发送,则取消该请求,创建一个新请求
x = new XMLHttpRequest(); // 对象创建出来了,此时肯定在发送Ajax请求 true
// 修改 标识变量的值
isSending = true;
x.open("GET",'http://127.0.0.1:8000/delay');
x.send();
// 当整个状态为4 时 请求完成
// 不需要加状态码判断,很可能请求是一个失败请求,如果在成功里面做判断,这个变量永远不能为false
x.onreadystatechange = function() {
if(x.readyState === 4) {
// 修应该标识变量
isSending = false;
}
}
}
</script>
</body>
</html>