大家好~ 今天写份笔记 记录一下学了2天的AJAX 并对知识进行梳
在这篇文章中,我将介绍AJAX基础知识、HTTP协议相关 AJAX相关工具、AJAX的简单使用方法 、AJAX的超时与网络异常、利用axios函数和fetch函数发送异步请求、解决跨域问题的策略等.
AJAX基础知识
- AJAX aka Asynchronous Javascript And XML. 即异步JavaScript和XML
- AJAX最大优势 : 网页在不刷新的情况下向服务器发送请求,允许用户更新部分页面的内容(聪数据库中提取)
- AJAX缺点 : 无浏览历史 不能回退 存在跨域问题
- AJAX依旧用JS作为语言
- 异步请求有三种: 普通事件 资源加载 定时器
- 常见的使用场合 : 搜索栏弹出相关加载(懒加载) 检测用户名是否重名等
HTTP协议的一些相关知识
学习AJAX需要具备一定的HTTP协议知识 我简略的叙述一下
HTTP协议分为 客户端请求消息(请求) 与 服务器响应消息(响应) 两部分
请求格式:
请求行: get(post)/url/httpVersion
请求头: Host、Cookie、Content-type、User-Agent(格式为键值对)
空行
请求体
需要注意的是 在get请求,请求体只能为空 在post请求中,请求体中可以不为空
响应格式:
行:HTTPVerison/响应状态码(200)/响应状态字符串(ok)
头:Content-type:text/hmcl;charset=utf-8 Content-length:2048
空行
响应体
需要注意的是响应报文中的响应体一般都是一个html文件<html>...<html/>
AJAX使用到的一些工具(这些是我学习的时候用的 不一定要一样)
VSCODE的下载
VSCODE直接下载 Visual Studio Code - Code Editing. Redefined
EXPRESS的下载(包括node.js)
安装node.js 下载 | Node.js 中文网 选择合适自己计算机的安装包下载
接下来安装express
- 首先以管理员启动VSCODE
- 右键一个项目(最外层的文件夹),选择在集成终端打开
- 输入命令npm init --yes (此时会出现package-lock.json和package.json文件)
- 执行命令npm i express
此时就安装成功了
NODEMON(一个可以在改变服务端代码之后重新启动服务的工具)
直接在终端上输入回车即可
npm install -g nodemon
准备工作已经完成 接下来就是具体的AJAX操作方法
AJAX简单使用方法
客户端
客户端使用AJAX发送请求的四大步骤
GET方法实例
{
// 进行ajax操作
// 1 创建对象
const xhr = new XMLHttpRequest();
// 2 初始化 设置请求方法和url
// xhr.open('GET', 'http://127.0.0.1:8000/server');
// 可以对url进行追加参数
// xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');
// 3 发送
xhr.send();
// 4 绑定事件 处理服务端返回的结果
// readystate是xhr的属性,有0(初始化)、1(open)、2(send)
// 3(服务端返回部分结果)、4(服务端返回所有结果)五个值
xhr.onreadystatechange = function () {
// 此函数要触发4次,每次改变状态的时候会触发 因此要判断状态
// 若返回所有的结果
if (xhr.readyState == 4) {
// 响应状态码为ok时 处理数据
if (xhr.status >= 200 && xhr.status <= 300) {
// 响应行 响应头
// 控制台中显示请求报文的相关信息和响应报文
console.log(xhr.status);
console.log(xhr.statusText);
console.log(xhr.getAllResponseHeaders());
console.log(xhr.response);
// 点击按钮,从服务端获取数据就大功告成了!
}
}
}
}
POST方法实例
{
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://127.0.0.1:8000/server');
// --------------------------
// 设置请求头 接收键值对
// xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
// Content - type 设置请求体的类型
// 自定义头信息可以设置 但浏览器会报错
// xhr.setRequestHeader('name', 'Jess');
// --------------------------------- 以上东西有风险
// POST可以设置请求体,包含请求参数
xhr.send('a=100&b=200&c=300');
// xhr.send('a:100&b:200&c:300');
// xhr.send('1234567890');
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status <= 300) {
result.innerHTML = xhr.response;
}
}
}
}
服务端
服务端对请求做出响应
const { request } = require('express');
const { response } = require('express');
const { application } = require('express');
const { json } = require('express/lib/response');
// ----------------------------------
// 1 引入express(有了这句会生成上面的4行代码)
const express = require('express');
// ----------------------------------
// ----------------------------------
// 2 创建应用对象
const app = express();
// ----------------------------------
// ----------------------------------
// 3 创建路由规则
// 创建路由规则 请求报文和响应报文 get请求和post请求的路由规则不同
// ----------------------------------
// server作为url 响应在客户端对应的url
app.get('/server',(request,response)=>{
// 设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置响应
// 此处尽情发挥
response.send('Hello-RESPONSE-AJAX');
})
// post这里实际上不能运行,因为在客户端已经自定义了请求头
app.post('/server',(request,response)=>{
// 设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置允许接收所有类型的请求头 但此时浏览器还有一个OPTION类型的请求进行校验 将post改为all即可
response.setHeader('Access-Control-Allow-Header','*')
// 设置响应体
response.send('Hello AJAXPOST');
})
// 应该用all方法来处理POST中设置自定义的请求头
app.all('/server',(request,response)=>{
// 设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置允许接收所有类型的请求头 但此时浏览器还有一个OPTION类型的请求进行校验 将post改为all即可
response.setHeader('Access-Control-Allow-Headers','*');
// 设置响应体
response.send('HelloAJAXPOSTDeam');
})
// 8000是一个端口,开启服务的时候占的端口号(可自定义)
app.listen(8000,()=>{
console.log("服务已启动,端口8000正在监听......");
})
AJAX的超时与网络异常
- onerror()当网络异常时执行的回调函数
- abort()取消发送请求
- ontimeout()超过timeout规定的时间则执行函数
重复发送请求
设置一个标志,记录是否已经发送请求,如果是,则取消当前请求并重新发送请求
// 解决重复发送请求问题 降低服务器压力
{
let isSending = false;
if (isSending) {
xhr.abort();
}
const xhr = new XMLHttpRequest();
isSending = true;
// 超时设置
xhr.timeout = 2000;
// 超时回调
xhr.ontimeout = () => {
alert('发送超时!请稍后重试')
}
// 网络异常
xhr.onerror = () => {
alert('网络异常');
}
xhr.open('GET', 'http://127.0.0.1:8000/server');
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
isSending = false;
}
}
});
利用axios函数和fetch函数发送异步请求
axios函数
AXIOS是Vue 和 React 推荐的AJAX API 官方文档 : axios中文网|axios API 中文文档 | axios
用script标签引入即可使用
axios函数使用方法
<script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.js"></script>
<!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>
<!-- <script src="https://unpkg.com/axios/dist/axios.min.js"></script> -->
<script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.js"></script>
</head>
<body>
<button>GET</button>
<button>POST</button>
<button>AXIOS</button>
<script>
const btn = document.querySelectorAll('button');
// get方法 url用'' 导入
// 创建axios实例
btn[0].onclick = function () {
axios.get('http://127.0.0.1:8000/axios-server', {
params: {
ID: 12345
}
})
}
// post方法第一个{}中必须是请求体,请求参数和请求头以对象的形式写入
btn[1].onclick = function () {
axios.post('http://127.0.0.1:8000/axios-server', {
username: 'Jess'
}, {
params: {
id: 123123
},
headers: {
name: 'Jess'
}
});
}
// 推荐AXIOS发送请求
// 将所有的参数都写在一起 方便快捷
// method和url必须写出并在首位
btn[2].onclick = function () {
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/axios-server',
params: {
id: 10,
level: 30
},
headers: {
a: 100,
b: 200
},
data: {
username: 'admin',
pwd: 'admin'
}
}).then(response => {
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
// 响应体
console.log(response.data);
})
}
</script>
</body>
</html>
//服务端
//--------------------------
// 响应axios
app.all('/axios-server',(request,response)=>{
// 设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置允许接收所有类型的请求头 但此时浏览器还有一个OPTION类型的请求进行校验 以all即可
response.setHeader('Access-Control-Allow-Headers','*');
// 设置响应体
response.send('HelloAJAXAXIOS');
})
fetch函数
fetch()也可以发送AJAX请求
这里提一下,服务器发送JSON对象
fetch('http://127.0.0.1:8000/fetch-server', {
// 请求方法
method: 'POST',
// 请求头
headers: {
name: 'Jess'
},
// 请求体
body: 'username=admin&password=admin'
}).then(response => {
// text是一个对response.content内容进行解码的一个函数
// console.log(response);
return response.text();
// 如果返回的是一个JSON对象
// return response.json();
}).then(response => {
console.log(response);
})
//服务端
app.all('/fetch-server',(request,response)=>{
// 设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置允许接收所有类型的请求头 但此时浏览器还有一个OPTION类型的请求进行校验 以all即可
response.setHeader('Access-Control-Allow-Headers','*');
// 设置响应体
response.send('HelloAJAXFETCH');
})
解决跨域问题的策略
同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响
同源需要做到 : 协议、域名、端口都要相同
解决方法1
在路由规则中设置响应头:
设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
解决方法2
JSONP 即通过script标签引用路由规则的方法
此方法最常用 但也有许多坑,需要注意服务器返回的东西需要让Javascript解析因此不能乱传数据.
<body>
用户名:<input type="text" id="username">
<p></p>
<script>
const input = document.getElementById('username');
function handle(data) {
const p = document.querySelector('p');
p.innerHTML = data.msg;
}
input.onblur = function () {
let uname = this.value;
// 发送请求
const script = document.createElement('script');
script.src = 'http://127.0.0.1:8000/check-server';
// 在body中追加script节点
document.body.append(script);
}
</script>
</body>
app.all('/JSONP-server',(request,response)=>{
// jsonp就是利用script标签不受同源策略限制的这一点,通过get的方式执行后端返回的js脚本
// 重点在是只能用GET方式执行
const data ={
name:'Jess'
}
let str = JSON.stringify(data);
// 使用end函数
// ${ }是es6新增的字符串方法,可以配合``单反引号完成字符串拼接的功能
// 用法:(1). 定义需要拼接的字符串
// (2). 将字符串用${ }包起来,写到需要拼接的地方
// 返回结果
response.end(`handle(${str})`);
// 返回结果不想其他服务一样,如果用JSONP服务的话单纯返回数据 浏览器无法解析
// 因为是引用 所有返回的数据需要Javascript解析
// 因此需要返回JS语句或者函数等可被解析的代码
})
结语:
写了这么多,花了2、3个小时整理,期间遇到不太理解的又重新学习一番
学时2天 将学过知识总结凝练 以供以后思考反思
希望走过路过的大佬们 指出问题 不胜感激!