Axios

2334 字
12 分钟
Axios

创建 API#

API 的分类#

  1. REST API: restful (Representational State Transfer (资源)表现层状态转化)
    1. 发送请求进行CRUD 哪个操作由请求方式来决定
    2. 同一个请求路径可以进行多个操作
    3. 请求方式会用到GET/POST/PUT/DELETE
  2. 非REST API: restless
    1. 请求方式不决定请求的CRUD 操作
    2. 一个请求路径只对应一个操作
    3. 一般只有GET/POST

使用json-server 搭建REST API#

json-server#

json-server 是用来快速搭建REST API 的工具包

使用json-server#

  1. 在线文档: https://github.com/typicode/json-server
  2. 下载: npm install -g json-server
  3. 目标根目录下创建数据库 json 文件: db.json
{
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" },
{ "id": 2, "title": "json-server2", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
  1. 启动服务器执行命令: json-server --watch db.json
  2. 使用浏览器访问测试 http://localhost:3000/posts

XHR 的 ajax封装 (简单版axios)#

特点#

  1. 函数的返回值为promise, 成功的结果为response, 失败的结果为error
  2. 能处理多种类型的请求: GET/POST/PUT/DELETE
  3. 函数的参数为一个配置对象
{
url: '', // 请求地址
method: '', // 请求方式GET/POST/PUT/DELETE
params: {}, // GET/DELETE 请求的 query 参数
data: {}, // POST/PUT 请求的请求体参数
}
  1. 响应 json数据 自动解析为 js的对象/数组

编码实现#

function axios({ url, method = 'GET', params = {}, data = {} }) {
// 返回一个promise对象
return new Promise((resolve, reject) => {
// 处理method 转大写
method = method.toUpperCase()
// 处理 query参数(拼接到url上)id=1&xxx=abc
let queryString = ''
Object.keys(params).forEach((key) => {
queryString += `${key}=${params[key]}&`
})
if (queryString) {
// 去除最后的'&'
queryString = queryString.substring(0, queryString.length - 1)
// 接到url
url += '?' + queryString
}
// 1. 执行异步Ajax请求
// 创建xhr对象
const request = new XMLHttpRequest()
// 打开连接(初始化请求,没有请求)
request.open(method, url, true)
// 发送请求
if (method === 'GET' || method === 'DELETE') {
request.send() // undefined
} else if (method === 'POST' || method === 'PUT') {
// 设置请求头,告诉服务器请求体的格式是json
request.setRequestHeader(
'Content-Type',
'appliaction/json;charset=utf-8'
)
// 发送json格式请求参数
request.send(JSON.stringify(data)) // 异步执行
}
// 绑定状态改变的监听
request.onreadystatechange = function () {
// 同步执行
// 如果请求没有完成,直接结束
if (request.readyState !== 4) {
return
}
// 如果响应状态码在[200, 300)之间代表成功,否则失败
const { status, statusText } = request
if (status >= 200 && status <= 299) {
// 2.1 如果请求成功,调用resolve()
// 准备结果数据对象response
const response = {
data: JSON.parse(request.response),
status,
statusText,
}
resolve(response)
} else {
// 2.2 如果请求失败,调用reject()
reject(new Error('request error status is ' + status))
}
}
})
}

使用测试#

// 1. GET请求:从服务器端获取数据
function testGet() {
axios({
url: 'http://localhost:3000/posts',
method: 'GET',
params: {
id: 1,
xxx: 'abc',
},
}).then(
(response) => {
console.log(response)
},
(error) => {
alert(error.message)
}
)
}
// 2. POST请求:向服务器端添加数据
function testPost() {
axios({
url: 'http://localhost:3000/posts',
method: 'POST',
data: {
title: 'json-server_post',
author: 'typicode_post',
},
}).then(
(response) => {
console.log(response)
},
(error) => {
alert(error.message)
}
)
}
// 3. PUT请求:服务器更新数据
function testPut() {
axios({
url: 'http://localhost:3000/posts/1',
method: 'PUT',
data: {
title: 'json-server_put',
author: 'typicode_put',
},
}).then(
(response) => {
console.log(response)
},
(error) => {
alert(error.message)
}
)
}
// 4. DELETE请求:服务器删除数据
function testDelete() {
axios({
url: 'http://localhost:3000/posts/2',
method: 'delete',
}).then(
(response) => {
console.log(response)
},
(error) => {
alert(error.message)
}
)
}

axios 的理解和使用#

axios 是什么#

  1. 前端最流行的 ajax请求库
  2. react/vue 官方都推荐使用 axios 发ajax 请求
  3. 文档: https://github.com/axios/axios

axios 特点#

  1. 基于 xhr + promise 的异步 ajax请求库
  2. 浏览器端/node 端都可以使用
  3. 支持请求/响应拦截器
  4. 支持请求取消
  5. 请求/响应数据转换
  6. 批量发送多个请求

axios 常用语法#

  • axios(config): 通用/最本质的发任意类型请求的方式
  • axios(url[, config]): 可以只指定url 发get 请求
  • axios.request(config): 等同于axios(config)
  • axios.get(url[, config]): 发get 请求
  • axios.delete(url[, config]): 发delete 请求
  • axios.post(url[, data, config]): 发post 请求
  • axios.put(url[, data, config]): 发put 请求
  • axios.defaults.xxx: 请求的默认全局配置(method\baseURL\params\timeout…)
  • axios.interceptors.request.use(): 添加请求拦截器
  • axios.interceptors.response.use(): 添加响应拦截器
  • axios.create([config]): 创建一个新的axios(它没有下面的功能)
  • axios.Cancel(): 用于创建取消请求的错误对象
  • axios.CancelToken(): 用于创建取消请求的 token 对象
  • axios.isCancel(): 是否是一个取消请求的错误
  • axios.all(promises): 用于批量执行多个异步请求
  • axios.spread(): 用来指定接收所有成功数据的回调函数的方法

使用示例#

GET 请求#

// 为给定 ID 的 user 创建请求
axios
.get('/user?ID=12345')
.then(function (response) {
console.log(response)
})
.catch(function (error) {
console.log(error)
})
// 可选地,上面的请求可以这样做
axios
.get('/user', {
params: {
ID: 12345,
},
})
.then(function (response) {
console.log(response)
})
.catch(function (error) {
console.log(error)
})

通过语法糖发送GET请求#

axios(config)
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone',
},
})
// 发送 GET 请求(默认的方法)
axios('/user/12345')
// 发送 GET 请求(axios.get方法)
axios.get('/user/12345')

重点注意#

axios.create(config)#

  1. 根据指定配置创建一个新的 axios, 也就是每个新 axios 都有自己的配置
  2. 新 axios 只是没有取消请求和批量发请求的方法, 其它所有语法都是一致的
  3. 为什么要设计这个语法?
    • 需求: 项目中有部分接口需要的配置与另一部分接口需要的配置不太一样, 如何处理(比如有多个baseURL需要指定)
    • 解决: 创建2 个新axios, 每个都有自己特有的配置, 分别应用到不同要求的接口请求中
const instance = axios.create({
// instance是函数类型
baseURL: 'http://localhost:3000',
})
// 使用instance发Ajax请求
instance({
url: '/posts',
})
instance.get('/posts')

拦截器函数的调用顺序#

  1. 说明: 调用axios()并不是立即发送ajax 请求, 而是需要经历一个较长的流程
  2. 流程: 请求拦截器2 => 请求拦截器1 => 发ajax 请求 => 响应拦截器1 => 响应拦截器2 => 请求的回调
  3. 注意: 此流程是通过 promise 串连起来的, 请求拦截器传递的是config, 响应拦截器传递的是response
// 添加两个请求拦截器(回调函数)
axios.interceptors.request.use(
(config) => {
console.log('request interceptor1 onResolved()') // -----------2
return config
},
(error) => {
console.log('request interceptor1 onRejected()')
return Promise.reject(error)
}
)
axios.interceptors.request.use(
(config) => {
console.log('request interceptor2 onResolved()') // -----------1
return config
},
(error) => {
console.log('request interceptor2 onRejected()')
return Promise.reject(error)
}
)
// 添加两个响应拦截器
axios.interceptors.response.use(
(resopnse) => {
console.log('response interceptor1 onResolved()') // -----------3
return resopnse
},
(error) => {
console.log('response interceptor1 onRejected()')
return Promise.reject(error)
}
)
axios.interceptors.response.use(
(resopnse) => {
console.log('response interceptor2 onResolved()') // -----------4
return resopnse
},
(error) => {
console.log('response interceptor2 onRejected()')
return Promise.reject(error)
}
)
axios
.get('http://localhost:3000/posts')
.then((response) => {
console.log('data', response.data) //data Array(4) -------------5
})
.catch((error) => {
cosole.log('error', error.message)
})
// request interceptor2 onResolved()
// request interceptor1 onResolved()
// response interceptor1 onResolved()
// response interceptor2 onResolved()
// data Array(4)

取消请求#

基本流程#

  1. 配置 cancelToken 对象
  2. 缓存用于取消请求的 cancel 函数
  3. 在后面特定时机调用 cancel 函数取消请求
  4. 在错误回调中判断如果 error 是 cancel, 做相应处理

实现功能#

在请求一个接口前, 取消前面一个未完成的请求

let cancel // 用于保存取消请求的函数
function getProducts1() {
// 在准备发请求前,取消未完成的请求
if (typeof cancel === 'function') {
cancel('取消请求')
}
axios({
url: 'http://localhost:4000/products1',
cancelToken: new axios.CancelToken(function executor(c) {
// c是用于取消当前请求的函数
// 保存取消函数,用于之后可能需要取消当前请求
cancel = c
}),
}).then(
(response) => {
cancel = null
console.log('请求1成功了', response.data)
},
(error) => {
if (axios.isCancel(error)) {
console.log('请求1取消的错误', error.message)
} else {
// 请求出错了
cancel = null
console.log('请求1失败了', error.message, error) // 请求1失败了 强制取消请求 Cancel {message: "强制取消请求"}
}
}
)
}
function getProducts2() {
// 在准备发请求前,取消未完成的请求
if (typeof cancel === 'function') {
cancel('取消请求')
}
axios({
url: 'http://localhost:4000/products2',
cancelToken: new axios.CancelToken(function executor(c) {
cancel = c
}),
}).then(
(response) => {
cancel = null
console.log('请求2成功了', response.data)
},
(error) => {
if (axios.isCancel(error)) {
console.log('请求2取消的错误', error.message)
} else {
cancel = null
console.log('请求2失败了', error.message, error)
}
}
)
}
function cancelReq() {
// 执行取消请求的函数
if (typeof cancel === 'function') {
cancel('强制取消请求')
} else {
console.log('没有可取消的请求')
}
}

使用拦截器,减少重复代码#

// 添加请求拦截器
axios.interceptors.request.use((config) => {
// 只写一个成功的回调
// 在准备发请求前,取消未完成的请求
if (typeof cancel === 'function') {
cancel('取消请求')
}
// 添加一个cancelToken的配置
config.cancelToken = new axios.CancelToken(function executor(c) {
// c是用于取消当前请求的函数
// 保存取消函数,用于之后可能需要取消当前请求
cancel = c
})
return config
})
// 添加响应拦截器
axios.interceptors.response.use(
(response) => {
// 成功的回调
cancel = null
return response
},
(error) => {
// 失败的回调
if (axios.isCancel(error)) {
// 请求取消的错误
console.log('请求取消的错误', error.message)
// 中断promise链
return new Promise(() => {})
} else {
// 请求出错了
cancel = null
// 将错误向下传递
// throw error
return Promise.reject(error)
}
}
)
let cancel // 用于保存取消请求的函数
function getProducts1() {
axios({
url: 'http://localhost:4000/products1',
}).then(
(response) => {
console.log('请求1成功了', response.data)
},
(error) => {
// 只用处理请求失败的情况,取消请求的错误不用处理
console.log('请求1失败了', error.message, error)
}
)
}
function getProducts2() {
axios({
url: 'http://localhost:4000/products2',
}).then(
(response) => {
console.log('请求2成功了', response.data)
},
(error) => {
console.log('请求2失败了', error.message, error)
}
)
}
function cancelReq() {
if (typeof cancel === 'function') {
cancel('强制取消请求')
} else {
console.log('没有可取消的请求')
}
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Axios
https://sukksa.github.io/posts/axios/
作者
Sukksa
发布于
2021-11-25
许可协议
CC BY-NC-SA 4.0
相关文章智能推荐
1
Ajax跨域
Ajax同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。 所…
2
Fetch
Ajaxfetch 是一种 HTTP 数据请求的方式,是 XMLHttpRequest 的一种替代方案。fetch 不是 ajax 的进一步封装,而是原生 js。Fetch 函数就是原生 js,没有使用 XMLHttpRequest 对象
3
原生Ajax
AjaxAjax 全称 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),既是一个对象,也是一种方法模式 AJAX 是一种用于创建快速动态网页的技术,通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网…
4
react-hooks
reactReact 的核心是组件。v16.8 版本之前,组件的标准写法是类(class)。 任何一个组件,可以用类来写,也可以用钩子来写。下面是类的写法。 再来看钩子的写法,也就是函数。 官方推荐使用钩子(函数),而不是类。因为钩子更简洁,代码量少,用起来比较"轻",而类比较"重"。而且,钩子是函数,更符合…
5
关于 cesium 在 micro-app 下无法显示的问题
cesium基座:vite + vue3 子应用:vite + vue3 micro app v1.0.0 rc.29, cesium v1.135 子应用包含一个 cesium map,在基座打开子应用时,cesium 无法显示地图,但是 sence, sky box, model 都能正常显示,唯独地图不显…
随机文章随机推荐
Profile Image of the Author
Sukksa
记录前端学习与日常
公告
博客刚刚上线,内容还在慢慢补齐。欢迎随便逛逛~
分类
标签
最新动态
站点统计
文章
69
分类
16
标签
17
总字数
178,517
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录