【ajax请求】Xhr → ajax→ axios
Asynchronous Javascript And XML, a(async异步)j(JavaScript)a(and)x(XML:与json同级语言格式)
ajax 作为前端必修课,页面无刷新获取数据。是一种创建动态网页(即前后端交互)的技术。
原理:浏览器底部抛出 XMLHttpRequest(简写XHR) 接口,XHR是用于对象和服务器的交互。
ajax请求函数本质上是对XHR封装,axios则是用promise对ajax的封装库。axios仍是学习重点。
打开Chrome浏览器里Network选项卡里的Fetch/Xhr一栏即为ajax请求。
XMLHttpRequest XHR
XMLHttpRequest 属性
XMLHttpRequest.onreadystatechange: 监控事件,当 xhr.readyState 属性发生改变触发
XMLHttpRequest.readyState: xhr的状态0-4共五个状态码,请求响应过程的当前活动阶段
XMLHttpRequest.onload=callback: 请成功并完成时触发,进入callback内代表readyState已经为4
XMLHttpRequest.status: 响应的http状态
XMLHttpRequest.response: 返回响应体
XMLHttpRequest.responseType : 指定响应体格式
XMLHttpRequest.responseType : 设置超时时间
XMLHttpRequest 对象的 readyState 属性,表示请求响应过程的当前活动阶段:
0: 未初始化,创建了XMLHttpRequest对象,但未调用open()方法
1: 启动,已经调用open()方法,但未调用send()方法
2: 发送,已经调用send()方法,但未接收到响应
3: 接收,已经接收到部分响应数据
4: 完成,已经接收到全部响应数据,并且可以在客户端使用
XMLHttpRequest 方法
XMLHttpRequest.open(method, url, async): 打开要发送请求的地址,参数:请求方式、请求的url地址、请求是否异步的布尔值(默认true)
XMLHttpRequest.send(requsetBody): 发送请求(体)
XMLHttpRequest.setRequestHeader(key, value): 设置请求头
XMLHttpRequest.getResponseHeader(key): 获取响应头
XMLHttpRequest.abort(): 请求发出,立刻终止
ajax
手写一个ajax,没用promise
// 1.实例化xhr对象
const xhr = new XMLHttpRequest();
// 监控 xhr.readyState
xhr.onreadystatechange = () => { // xhr实例出来的那一刻为0
if (xhr.readyState === 4) { // xhr有五种状态0,1,2,3,4,其中4为完全接收状态
if (xhr.status > 200 && xhr.status < 300) {
// 2.指定发送请求的url地址:method、url带query参数、true开启异步
xhr.open('GET', 'http://localhost:8080/testrequest?name=paul&age=18',false)
// 3.发送请求
xhr.send()
}
}
}
★axios
axios 是一个基于promise 的 http 库,可以用于浏览器和 nodejs 中
用promise封装ajax,无状态
// 用promise封装一个axios请函数,传入参数config(对象包含1.请求路径2.请求方式3.)
function axios(config) {
// 调用axios方法,将返回一个promise实例
return new Promise((resolve, reject) => {
// 解构出config参数里的url、method、data
const { url = '', method = 'GET', data = {} } = config
// Xhr实例化
const xhr = new XMLHttpRequest()
// 指定要发送的请求(注意参数)
xhr.open(method, url, true)
// 请求完成时要执行的函数
xhr.onload = function () {
// 判断状态码
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText) // 返回成功的promise,
} else {
reject(new Error('faile')) // 返回失败的promise
}
}
// 发送请求
xhr.send()
})
}
ps:只要进入xhr.onload回调里,即代表xhr.onreadystatechange ===4,已经完成响应。
一、axios配置
axios有三种形式的配置,全局配置,实例配置,请求配置。
优先级:请求配置 > 实例配置 > 全局配置
全局配置
// axios全局默认值
axios.defaults.baseURL = 'http://localhost:8080';
axios.defaults.timeout = 1000 ;
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
实例配置
// axios实例配置(new axios出来的实例)
let request = axios.create({
baseURL:'http://localhost/api/', // URL基础路径
url: '/user', // 在baseURL路径后拼接完整url地址
method: 'GET', // 请求方式(默认get),get,post,put,patch,delete
params: { delay: 3000 }, // 参数用于GET请求,把数据拼接在URL的查询字符串中。配置url参数,虽然叫params配置但是携带的是query参数。
data: { c: 2, d: 3 }, // 参数放在请求体中(json参数),只使用于PUT,POST,PATCH
data: `e=4&f=6`, // 置请求主体(urlencode编码),只使用于PUT,POST,PATCH
timeout:2000, // 请求超时毫秒
headers:{'Content-Type': 'application/json;charset=UTF-8'}, // 自定义情头头
responseType:'json' // 指定响应格式(默认json),老项目可能用xml
})
请求配置
// axios请求配置
instance.get('/longRequest', { //// 为已知需要花费很长时间的请求覆写超时设置
timeout: 5000
});
二、axios拦截器
axios拦截器分为请求拦截器和响应拦截器。
拦截器的作用,在发起请求前做些什么,在响应回来前做些什么。
在发起请求或响应被 then 或 catch 处理前拦截它们
axios.get().then().catch(err=>{})
axios请求拦截器
// 请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
// 此处为通过携带token字段控制登录状态
axios.interceptors.request.use((config) => {
// config:配置对象,对象里面有一个属性很重要,headers请求头
// 在发送请求之前做些什么,给拦截器设置过滤
if (condition) {
config.headers.token = ''
}
// 将axios的config配置返回出去,不然起不到过滤作用
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
axios响应拦截器
// 响应拦截器:在请求返回之前,响应拦截器可以检测到
axios.interceptors.response.use((response) => {
// 拦截成功做些什么,返回成功的数据数据
if (condition) {
// axios发送请求的数据返回都是双层data,这里利用响应拦截器自动脱掉一层data
return response.data
}
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
三、axios 二次封装写法 (转载自https://www.jianshu.com/p/d6796986e2ab)
// request.js
import axios from 'axios';
import NProgress from 'nprogress';
import { notification, message } from 'antd';
import { routerRedux } from 'dva/router';
import store from '../index';
/**
* 一、功能:
* 1. 统一拦截http错误请求码;
* 2. 统一拦截业务错误代码;
* 3. 统一设置请求前缀
* |-- 每个 http 加前缀 baseURL = /api/v1,从配置文件中获取 apiPrefix
* 4. 配置异步请求过渡状态:显示蓝色加载条表示正在请求中,避免给用户页面假死的不好体验。
* |-- 使用 NProgress 工具库。
*
* 二、引包:
* |-- axios:http 请求工具库
* |-- NProgress:异步请求过度条,在浏览器主体部分顶部显示蓝色小条
* |-- notification:Antd组件 > 处理错误响应码提示信息
* |-- routerRedux:dva/router对象,用于路由跳转,错误响应码跳转相应页面
* |-- store:dva中对象,使用里面的 dispatch 对象,用于触发路由跳转
*/
// 设置全局参数,如响应超市时间,请求前缀等。
axios.defaults.timeout = 5000
axios.defaults.baseURL = '/api/v1';
axios.defaults.withCredentials = true;
// 状态码错误信息
const codeMessage = {
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
204: '删除数据成功。',
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(令牌、用户名、密码错误)。',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
};
// 添加一个请求拦截器,用于设置请求过渡状态
axios.interceptors.request.use((config) => {
// 请求开始,蓝色过渡滚动条开始出现
NProgress.start();
return config;
}, (error) => {
return Promise.reject(error);
});
// 添加一个返回拦截器
axios.interceptors.response.use((response) => {
// 请求结束,蓝色过渡滚动条消失
NProgress.done();
return response;
}, (error) => {
// 请求结束,蓝色过渡滚动条消失
// 即使出现异常,也要调用关闭方法,否则一直处于加载状态很奇怪
NProgress.done();
return Promise.reject(error);
});
export default function request(opt) {
// 调用 axios api,统一拦截
return axios(opt)
.then((response) => {
// >>>>>>>>>>>>>> 请求成功 <<<<<<<<<<<<<<
console.log(`【${opt.method} ${opt.url}】请求成功,响应数据:%o`, response)
// 打印业务错误提示
if (response.data && response.data.code != '0000') {
message.error(response.data.message);
}
return { ...response.data };
})
.catch((error) => {
// >>>>>>>>>>>>>> 请求失败 <<<<<<<<<<<<<<
// 请求配置发生的错误
if (!error.response) {
return console.log('Error', error.message);
}
// 响应时状态码处理
const status = error.response.status;
const errortext = codeMessage[status] || error.response.statusText;
notification.error({
message: `请求错误 ${status}`,
description: errortext,
});
// 存在请求,但是服务器的返回一个状态码,它们都在2xx之外
const { dispatch } = store;
if (status === 401) {
dispatch(routerRedux.push('/user/login'));
} else if (status === 403) {
dispatch(routerRedux.push('/exception/403'));
} else if (status <= 504 && status >= 500) {
dispatch(routerRedux.push('/exception/500'));
} else if (status >= 404 && status < 422) {
dispatch(routerRedux.push('/exception/404'));
}
// 开发时使用,上线时删除
console.log(`【${opt.method} ${opt.url}】请求失败,响应数据:%o`, error.response);
return { code: status, message: errortext };
});
}
接口api函数统一管理
// 发请求:axios发请求返回结果是Promise对象
// 对外暴露一个函数,只要外部调用这个函数,就向服务器发起ajax请求,当前者个函数只需要把服务器返回的结果返回即可
// 无参数
export const reqA = () => requests({
url: '/a',
method: 'GET',
})
// 若无接口,可以使用mock模拟数据。无参数
export const reqB = () => mockRequest({
url: '/b',
method: 'GET'
})
// 请求参数:params参数:,模板字符串手动拼入路径
export const reqC = (id) => requests({
url: `/d/${id}`,
method: 'GET'
})
// 请求参数:query参数,会写入路径
// 这里的params是指形参的意思(你可以写作任意),aioxs规定params配置项必须为对象,**所以这里params实际为是query参数**
// 若params:{name:paul},则最终请求的路径为 http://localhost/c?name=paul
export const reqD = (params) => requests({
url: '/c',
method: 'POST',
params
})
// 请求主体发送数据:data
// 给服务器传递参数params(这里的params是指形参的意思,aioxs规定data为对象)
export const reqE = (params) => requests({
url: '/e',
method: 'POST',
data: params
})
// 混合带参,很奇怪。 1.请求参数:params参数 2.请求体参数data
export const reqF = (params, data) => requests({
url: `/f/${params}`,
method: 'POST',
data
})
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本