Ajax详解
什么是ajax
- Ajax 全称为“Asynchronous Javascript And XML”级(异步 JavaScript 和 XML),是一种创建交互式网页应用的网页开发技术,用来实现前后端交互
- 其核心是XMLHTTPRequest对象,由浏览器提供。通过这个对象可以实现在不重新加载页面的情况下与Web服务器交换数据,使得程序能够更快地回应用户的操作,也就是说ajax可以实现网页的局部刷新
- 由于每次发出ajax请求都要写很多相同的代码,一个页面一般都有好几个请求,那么会有冗余代码,不仅影响前端开发效率,还影响代码可维护性和可读性,所以可以对ajax进行封装
- 因为js是单线程的编程语言,一般情况下ajax都会用异步的方式,否则会阻塞后续js代码执行,出现卡顿,影响效率
- 可以使用promise进一步完善对原生ajax的封装,使用resolve来接收服务器返回的数据,然后用.then方法获取返回结果;同时也可以利用 async/await 语法进一步简化代码
- axios就是一种通过Promise对ajax的封装,是一个基于Promise的Http库,可以在浏览器和Node.js中使用,可以直接调用.then方法获取服务器返回的数据;axios可以自动转换JSON数据,不需要再用JSON.parse()方法,并且支持配置ajax的请求与响应拦截器,比如可以往里面添加nprogress进度条组件优化用户体验;请求拦截器:发送请求的时候,携带一些信息,比如说token,就是令牌,在用户向服务端请求数据时进行校验,提高安全性;响应拦截器:接收到数据的时候,进行数据过滤、对状态码判断等对应的操作
- axios是一个第三方库,需要通过npm安装后使用;而ajax是JavaScript的内置对象,无需安装就可以使用,直接new操作
ajax常见的请求方式
● GET:表示向服务器获取资源
● POST:表示向服务器提交信息,通常用于产生新的数据,比如注册
● PUT:表示希望修改服务器的数据, 通常用于修改某数据
● DELETE:表示希望删除服务器的数据
● OPTIONS:发生在跨域的预检请求中,表示客户端向服务器申请跨域提交
GET和POST请求数据区别
- 使用Get请求时,参数在URL中显示,直接拼接在请求路径后,用一个?间隔,而使用Post请求方式,则请求参数放在xhr.send()里面,并且Post请求需要请求头
- 使用Get请求时只能携带查询字符串格式;而使用Post请求方式,原则上不限制格式, 但是需要在请求报文的 content-type 做出配置
- 使用Get请求发送数据量小(2kb左右),Post请求发送数据量大
- 使用Get请求是明文发送,因为在传输过程,数据被放在请求的URL中,URL中数据会被记录到日志文件,泄漏信息的风险,相对不安全;使用Post请求是暗文发送,Post的所有操作对用户来说都是不可见的,相对安全
老版的ajax
get请求
const xhr = new XMLHttpRequest();
xhr.open("get","请求url?查询字符串",true)
xhr.send()
//获取服务器响应的数据
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
//获取服务器响应的数据
xhr.responseText
}
}
post请求
const xhr = new XMLHttpRequest();
xhr.open("请求方式","请求URL",true)
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")
xhr.send(`查询字符串`)
//获取服务器响应的数据
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
//获取服务器响应的数据
xhr.responseText
}
}
ajax状态码有哪些
简单来说其实就是用一个数字表明了当前 ajax 运行到哪一步了。
语法: xhr.readyState
- 0: 创建 ajax 成功
- 1: 当前 ajax 配置成功
- 2: 当前 ajax 发送成功(响应已经回到浏览器了)
- 3: 表示浏览器当前正在解析本次响应, 但可能还没完成
- 4: 表示浏览器已经完成解析本次响应, 可以正常使用 responseText 了
- 0 和 1,比较好打印,2/3/4 这几个我们可以借助一个事件去打印。
readyStatechange 事件
通过事件名其实就可以看出,当 readyState 发生改变时就会执行。
const xhr = new XMLHttpRequest()
console.log(xhr.readyState) // 0
xhr.open('GET', 'http://localhost:8888/test/first', true)
console.log(xhr.readyState) // 1
xhr.onreadystatechange = function () {
if (xhr.readyState === 2) console.log(xhr.responseText)
if (xhr.readyState === 3) console.log(xhr.responseText)
if (xhr.readyState === 4) console.log(xhr.responseText)
}
xhr.send()
H5版ajax
get请求
const xhr = new XMLHttpRequest();
xhr.open("请求方式","请求URL?查询字符串",是否异步)
xhr.send();
xhr.onload = function(){
xhr.responseText
}
post请求
const xhr = new XMLHttpRequest();
xhr.open("请求方式","请求URL",是否异步)
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")
xhr.send("查询字符串");
xhr.onload = function(){
xhr.responseText
}
创建ajax的基本步骤
- 创建ajax对象
const xhr = new XMLHttpRequest()
- 配置ajax对象
// xhr.open('请求的方式', '请求的地址', 是否异步)
xhr.open('GET', 'http://localhost:8888/test/first', true)
- 发送请求
xhr.send()
- 接收响应
xhr.onload = function () {
console.log('请求回来了~~~~~~~~')
console.log(xhr.responseText)
}
封装版ajax
封装请求参数
请求方式 => get,post
请求URL => URL(不能为空)
请求参数 => 可以为空
是否异步
封装响应
响应的数据格式 => JSON,对象
函数 => 利用回调函数获取服务器的数据
<body>
<button>发送ajax</button>
<!-- 引入 -->
<script src="./utils.js"></script>
<script>
const btn = document.querySelector("button")
btn.onclick = function () {
Ajax({
url: "http://localhost:8080/login",
params: {username:'admin',password:123456},
success(data) {
console.log(data);
}
})
}
</script>
</body>
function Ajax(options) {
//如果没有URL地址,那么直接报错
if (!options.url) {
throw new Error("请输入请求的URL地址")
}
//设置默认值
const paramsDefault = {
url: "",//请求地址
type: "get",//请求类名默认为get请求
params: "",//请参数默认可以没有
async: true,//是否异步,默认为异步
resType: 'object',//默认获取的是对象数据
success() { },//响应的数据通过回调函数获取
}
//配置默认参数
for (let key in options) {
paramsDefault[key] = options[key]
}
//校验请求类型
if (!(paramsDefault.type.toUpperCase() == "GET" || paramsDefault.type.toUpperCase() == "POST")) {
throw new Error("请求类型为get或者post请求")
}
//请求参数是字符串
if (!(typeof paramsDefault.params == 'string' || Object.prototype.toString.call(paramsDefault.params) == '[object Object]')) {
throw new Error("请求参数是一个字符串")
}
let str = "";
if (Object.prototype.toString.call(paramsDefault.params) == '[object Object]') {
//将对象转换成查询字符串
// {username:admin,password:123456} => username=admin&password=123456
for (let key in paramsDefault.params) {
str += `${key}=${paramsDefault.params[key]}&`
}
str = str.slice(0,-1)
paramsDefault.params = str;
}
//判断请求是否异步
if (typeof paramsDefault.async != 'boolean') {
throw new Error("请求的数据类型是一个boolean类型")
}
//判断期望返回的数据类型
if (!(paramsDefault.resType.toUpperCase() == 'OBJECT' || paramsDefault.resType.toUpperCase() == 'STRING')) {
throw new Error('期望返回的数据类型是对象或者字符串')
}
//回调函数
if (Object.prototype.toString.call(paramsDefault.success) != '[object Function]') {
throw new Error("获取数据的方式->回调函数")
}
//配置发送Ajax
if (paramsDefault.type.toUpperCase() == 'GET') {
//发送get请求
const xhr = new XMLHttpRequest();
xhr.open("get", paramsDefault.url + "?" + paramsDefault.params, paramsDefault.async)
xhr.send();
xhr.onload = function () {
//如果paramsDefault.resType == 'object'
if (paramsDefault.resType.toUpperCase() == 'OBJECT') {
paramsDefault.success(JSON.parse(xhr.responseText))
} else {
paramsDefault.success(xhr.responseText)
}
}
} else {
//发送post请求
const xhr = new XMLHttpRequest();
xhr.open("post", paramsDefault.url, paramsDefault.async)
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded")
xhr.send(paramsDefault.params);
xhr.onload = function () {
//如果paramsDefault.resType == 'object'
if (paramsDefault.resType.toUpperCase() == 'OBJECT') {
paramsDefault.success(JSON.parse(xhr.responseText))
} else {
paramsDefault.success(xhr.responseText)
}
}
}
}
使用promise封装ajax
<button>发送ajax</button>
<script src="./utils.js"></script>
<script>
const btn = document.querySelector("button")
btn.onclick = function(){
axiosAjax({
url:"http://localhost:8080/login",
params:{username:"admin",password:123456}
})
.then(res=>{
console.log(res);
})
}
</script>
function Ajax(options) {
//如果没有URL地址,那么直接报错
if (!options.url) {
throw new Error("请输入请求的URL地址")
}
//设置默认值
const paramsDefault = {
url: "",//请求地址
type: "get",//请求类名默认为get请求
params: "",//请参数默认可以没有
async: true,//是否异步,默认为异步
resType: 'object',//默认获取的是对象数据
success() { },//响应的数据通过回调函数获取
}
//配置默认参数
for (let key in options) {
paramsDefault[key] = options[key]
}
//校验请求类型
if (!(paramsDefault.type.toUpperCase() == "GET" || paramsDefault.type.toUpperCase() == "POST")) {
throw new Error("请求类型为get或者post请求")
}
//请求参数是字符串
if (!(typeof paramsDefault.params == 'string' || Object.prototype.toString.call(paramsDefault.params) == '[object Object]')) {
throw new Error("请求参数是一个字符串")
}
let str = "";
if (Object.prototype.toString.call(paramsDefault.params) == '[object Object]') {
//将对象转换成查询字符串
// {username:admin,password:123456} => username=admin&password=123456
for (let key in paramsDefault.params) {
str += `${key}=${paramsDefault.params[key]}&`
}
str = str.slice(0,-1)
paramsDefault.params = str;
}
//判断请求是否异步
if (typeof paramsDefault.async != 'boolean') {
throw new Error("请求的数据类型是一个boolean类型")
}
//判断期望返回的数据类型
if (!(paramsDefault.resType.toUpperCase() == 'OBJECT' || paramsDefault.resType.toUpperCase() == 'STRING')) {
throw new Error('期望返回的数据类型是对象或者字符串')
}
//回调函数
if (Object.prototype.toString.call(paramsDefault.success) != '[object Function]') {
throw new Error("获取数据的方式->回调函数")
}
//配置发送Ajax
if (paramsDefault.type.toUpperCase() == 'GET') {
//发送get请求
const xhr = new XMLHttpRequest();
xhr.open("get", paramsDefault.url + "?" + paramsDefault.params, paramsDefault.async)
xhr.send();
xhr.onload = function () {
//如果paramsDefault.resType == 'object'
if (paramsDefault.resType.toUpperCase() == 'OBJECT') {
paramsDefault.success(JSON.parse(xhr.responseText))
} else {
paramsDefault.success(xhr.responseText)
}
}
} else {
//发送post请求
const xhr = new XMLHttpRequest();
xhr.open("post", paramsDefault.url, paramsDefault.async)
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded")
xhr.send(paramsDefault.params);
xhr.onload = function () {
//如果paramsDefault.resType == 'object'
if (paramsDefault.resType.toUpperCase() == 'OBJECT') {
paramsDefault.success(JSON.parse(xhr.responseText))
} else {
paramsDefault.success(xhr.responseText)
}
}
}
}
//ajax是一个异步代码 => 可以使用promise进行二次封装
function axiosAjax(options){
return new Promise((resolve,reject)=>{
Ajax({
url:options.url || '',
type: options.type || 'get',
params: options.params || '',
async: options.async || true,
resType: options.resType || 'object',//默认获取的是对象数据
success(data) {
//我们要的就是服务器返回的数据,使用resolve进行获取
resolve(data)
},
})
})
}
axios的用法
axios 是发送ajax的天花板
特点:可以给前端使用 还可以给服务器使用
axios的数据:返回值是在axios返回的data当中
1.导入axios的链接 => bootcdn官网 搜索axios下载axios.min.js
2.使用 => 直接翻官网 axios官网
不使用异步函数的情况
<body>
<script src="./axios.min.js"></script>
<button onclick="fn()">通过axios发送ajax</button>
<script>
function fn1(){
axios({
// method:"get" 默认就是get请求 所以可以不写
// get请求 那么请求参数为请求的url+"?"+查询字符串
url:`http://localhost:8080/login?username=admin&password=123456`
})
.then(res=>{
console.log(res.data);
})
}
function fn2(){
axios({
//post请求
method:"post",
url:"http://localhost:8080/reg",
data:{
username:"bingMIN",
password:123456
}
})
.then(res=>{
console.log(res.data);
})
}
</script>
</body>
使用异步函数 方式一
<body>
<script src="./axios.min.js"></script>
<button onclick="fn()">通过axios发送ajax</button>
<script>
async function fn1(){
const result = await axios({
// get请求 那么请求参数为请求的url+"?"+查询字符串
url:`http://localhost:8080/login?username=admin&password=123456`
})
console.log(result.data);
}
async function fn2(){
const result = await axios({
//post请求
method:"post",
url:"http://localhost:8080/reg",
data:{
username:"bingMIN",
password:123456
}
})
console.log(result.data);
}
</script>
</body>
使用异步函数 方式二
<body>
<script src="./axios.min.js"></script>
<button onclick="fn()">通过axios发送ajax</button>
<script>
async function fn1(){
// get请求
const result = await axios.get("http://localhost:8080/login?username=admin&password=123456")
console.log(result.data);
}
async function fn2(){
// post请求
const result = await axios.post("http://localhost:8080/reg",{username:"admin",password:123456})
console.log(result.data);
}
</script>
</body>
二次封装axios 配置ajax拦截器(请求与响应拦截器)
<script src="./axios.min.js"></script>
<button onclick="fn()">通过axios发送ajax</button>
<script>
/*
1.导入axios
2.创建axios请求实例
http://localhost:8080/reg
http://localhost:8080/login
http://localhost:8080/xxx
可以看到前面部分都是相同的 可以进行二次封装
baseURL => http://localhost:8080
3.配置ajax拦截器(请求与响应拦截器) 直接看axios官网 搜索拦截器的使用
4.ajax
*/
function fn(){
const instance = axios.create({
baseURL:"http://localhost:8080", //基本的请求路径
timeout:1000 //超时时间
})
// 配置请求与响应拦截器
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
console.log("请求拦截器");
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 对响应数据做点什么
console.log("响应拦截器");
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
// 发送get请求
/* instance({
url:"/login?username=wenyuan&password=123456"
})
.then(res=>{
console.log(res.data);
}) */
// 发送post请求
instance({
method:"post",
url:"/reg",
data:{
username:"admin",
password:123456
}
})
.then(res=>{
console.log(res.data);
})
}
</script>
ajax二次封装+nprogress的使用
nprogress的使用
1.导入第三方包nprogress的css和js文件 => bootcdn官网 搜索nprogress下载或直接用在线链接
2.nprogress使用方法 翻nprogress官网
NProgress.start() — 显示进度条
NProgress.set(0.4) —设置百分比
NProgress.inc() — 增加一点点
NProgress.done() — 完成进度条
<script src="./axios.min.js"></script>
<!-- 进度条的css和js行为 -->
<link href="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
<button onclick="fn()">通过axios发送ajax</button>
<script>
function fn(){
const instance = axios.create({
baseURL: 'http://localhost:8080',
timeout: 1000,
});
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
// 在请求的时候,开启进度条
NProgress.start()
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
//关闭进度条
NProgress.done()
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
instance({
method:"post",
url:"/reg",
data:{
username:"admin",
password:123456
}
})
.then(res=>{
console.log(res.data);
})
}
</script>
参考文章:Ajax和Ajax的封装
参考文章:JavaScript全解析——Ajax