这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战
axios (ajax i/o system) 是目前前端使用非常广泛的网络请求库
主要特点包括:在浏览器中发送 XMLHttpRequests 请求、在 node.js 中发送 http请求、支持 Promise API、拦截请求和 响应、转换请求和响应数据等等
基本使用
get请求
async componentDidMount() {
try {
// axios方法返回的都是一个promise
const res = await axios({
// get请求的参数可以写在url的地址后边
// 也可以写在params参数中,让axios库自动进行拼接
url: 'https://httpbin.org/get',
params: {
name: 'Klaus',
age: 24
}
})
console.log(res)
} catch(err) {
console.error(err.message)
}
}
async componentDidMount() {
try {
const res = await axios.request({
url: 'https://httpbin.org/get',
params: {
name: 'Klaus',
age: 24
}
})
console.log(res)
} catch(err) {
console.error(err.message)
}
}
语法糖写法
async componentDidMount() {
try {
// 参数1: url 参数2: 配置对象
const res = await axios.get('https://httpbin.org/get', {
params: {
name: 'Klaus',
age: 24
}
})
console.log(res)
} catch(err) {
console.error(err.message)
}
}
post请求
async componentDidMount() {
try {
const res = await axios.request({
url: 'https://httpbin.org/post',
data: {
name: 'Klaus',
age: 24
},
method: 'post' // 默认值是 post
})
console.log(res)
} catch(err) {
console.error(err.message)
}
}
语法糖写法
async componentDidMount() {
try {
// 参数1: url
// 参数2:需要传递的data
// 参数3: 配置对象
const res = await axios.post('https://httpbin.org/post', {
name: 'Klaus',
age: 24
})
console.log(res)
} catch(err) {
console.error(err.message)
}
}
async componentDidMount() {
const request1 = axios.post('https://httpbin.org/post', {
name: 'Klaus',
age: 24
})
const request2 = axios.get('https://httpbin.org/get', {
params: {
name: 'Klaus',
age: 24
}
})
try {
// axios.all本质上其实就是Promise.all
const res = await axios.all([request1, request2])
console.log(res)
} catch(err) {
console.error(err.message)
}
}
}
axios可以发送的请求有:
- axios(config)
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
在axios中,任何发送请求的方法,本质上的都是使用
axios.request方法发送请求的语法糖形式
axios本质上就是使用axios.request方法进行调用的
// 源码中的部分代码
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
// instance就是我们的axios本质上是一个函数
// 我们直接调用axios方法的时候,本质上就是在调用axios.request方法
var instance = bind(Axios.prototype.request, context); // Axios.prototype.request.apply(context)
// ....
return instance;
}
var axios = createInstance(defaults);
// bind方法
module.exports = function bind(fn, thisArg) {
return function wrap() {
// 这里的args其实就是wrap函数的参数
// 也就是我们调用axios方法传入的配置对象
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
return fn.apply(thisArg, args);
};
};
// axios的所有实例方法本质上调用的就是axios.request
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: (config || {}).data
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: data
}));
};
});
修改配置
默认情况下,axios会对我们返回的数据进行封装后再返回
而在很多情况下我们可能需要修改axios请求的默认配置
那么我们可以在入口文件中,对axios.defaults(也就是axios的默认配置信息)进行修改
index.js
import axios from 'axios'
// 修改baseURL
axios.defaults.baseURL = 'https://httpbin.org/'
// 任何请求都需要使用到的请求头配置
axios.defaults.headers.common['token'] = 'c9H1Vsb5tkAyqeW7FNKnH3Wqbw9Nl4JT';
// 单独请求特有的请求头单独配置
axios.defaults.headers.get.FOO = 'foo';
如果我们存在多个服务器的时候,我们可以使用axios.create方法创建多个axios实例来处理不同的服务器请求和响应
const api = axios.create({
baseURL: 'http://api.example.com/',
headers: Object.assign(axios.defaults.headers, {
common: {
token: 'c9H1Vsb5tkAyqeW7FNKnH3Wqbw9Nl4JT'
}
})
})
const one = axios.create({
baseURL: 'http://api-one.example.com/'
})
one.defaults.headers.common.token = 'gnS5OgNDtReokJbwgb7Sbki3RRhXLlPf'
如果存在多个配置项,那么他们之间的优先级是:
-
优先是请求的config参数配置
-
其次是实例的default中的配置
-
最后是创建实例时的配置
拦截器
我们可以使用axios的拦截器对axios的请求和响应进行拦截处理
// 请求拦截
// 参数1: onFulliflled
// 参数2: onRejected
axios.interceptors.request.use(config => {
// 1. 我们可以在这里加载请求中的loading
// 2. 我们可以在这里进行有没有token的判断 --- 鉴权操作
// 3. 我们对我们请求的参数进行二次转换
console.log(`向${config.url}发送了${config.method}请求`)
// 需要将配置选项传递给下一个方法进行使用的
return config
}, error => error) // 错误直接传递,不进行任何的处理 --- 不做处理其实是可以省略的
// 响应拦截
axios.interceptors.response.use(res => {
// 直接返回服务器真正返回我们的数据
return res.data
})
简单封装
默认情况下我们是可以直接使用axios来进行开发的
但是在实际开发中,我们会存在许多个文件中都需要使用到axios来进行网络请求
此时,如果某一天,我们需要对axios的配置进行调整,或者使用别的库来替换axios的时候
我们就需要去修改所有引入了axios的js文件,此时工作量和出错率都是很大的
所以我们在实际开发过程中,我们都会自己将axios请求进行二次封装
然后在项目代码中使用我们封装后的API
这样如果以后需要修改后替换axios的时候,就只要修改我们自己封装的哪几个js文件就可以了

src/service/consts.js
const devBaseURL = 'https://api-sit.example.com/'
const prodBaseURL = 'https://api.example.com/'
export const BASEURL = process.env.NODE_ENV === 'development' ? devBaseURL : prodBaseURL
export const TIMEOUT = 5000
src/service/api.js
import axios from 'axios'
import { BASEURL, TIMEOUT } from './consts'
const api = axios.create({
baseURL: BASEURL,
timeout: TIMEOUT
})
api.interceptors.response.use(res => res.data)
export default api
使用
api.post('http://httpbin.org/post', {
name: 'Klaus',
age: 24
})
.then(res => console.log(res))
.catch(console.log)
// 因为catch需要传递一个callback,参数会传递res
// 而console.log本质就是一个函数,其也可以接收一个或多个参数
// 所以我们可以在这里直接将console.log函数进行传入,作为onReject函数