概念

axios 有一点好,可以在浏览器和node环境中使用。

在浏览器中使用 XHR ,在node中使用 http 发送请求。支持promise,可拦截可取消

当然了, axios 大火的一个因素也是因为 vue 官方文档指名道姓推荐了 axios

image.png

快速入门

  1. const axios = require('axios')
  2. // url get
  3. axios.get('/user?v=2').then(res=>{}).catche().finally()
  4. // get 带参数
  5. axios.get('/user',{params:{ID:1}}).then().catch().then()
  6. // async/await
  7. async go(){
  8. try{
  9. const res = await axios.get('/user?v=2')
  10. }catch(err){log(err)}
  11. }
  12. // post
  13. axios.post('/user',{
  14. a:2,b:1
  15. }).then().catch()
  16. // 执行多个请求
  17. function a1(){return axios.get()}
  18. function a2(){return axios.get}
  19. axios.all([a1(),a2()]).then(axios.spread((acct,perms)=>{}))

api

axios(config)

  1. axios({
  2. method:'post',
  3. url:'',
  4. data:{
  5. a:1
  6. }
  7. })

使用 stream 下载图片

  1. axios({
  2. method:'get',
  3. url:'',
  4. responseType:'stream'
  5. }).then(res=>{
  6. res.data.pipe(fs.createWriteStream(a.jpg))
  7. })

axios(url[,config])

默认get

  1. axios(url)

其他

  • axios.request(config)
  • axios.get(url[,config])
  • axios.delete(url[,config])
  • axios.head

创建一个实例

  1. const i = axios.crate({
  2. baseURL:'',
  3. timeout:1000,
  4. headers:{}
  5. })
  6. i.get()

返回的结构

  1. var res = {
  2. data:{},
  3. status:200,
  4. statusText:'OK',
  5. headers:{},
  6. config:{}
  7. request:{}
  8. }

默认情况下,axios把 Javascropt 转为json,如果要使用application/x-www-form-urlencoded发送数据。

浏览器可以使用 qs库来编码

拦截器 interceptors

axios 可以对 requestresponse 进行拦截:

  • 在发出请求时候可以修改 请求头,比如带上token
  • 在收到相应时候可以对数据进行校验调整,比如判断 status 2xx 4xx 5xx

请看具体代码

  1. // 请求拦截器
  2. instance.interceptors.request.use((conf) => {
  3. if (!conf.headers['Authorization']) {
  4. conf.headers['Authorization'] = token();
  5. }
  6. return Promise.resolve(conf);
  7. });

注意这里的 error: AxiosError ,并不是普通的 Error 对象

  1. // 相应拦截器
  2. instance.interceptors.response.use(
  3. (res) => Promise.resolve(res),
  4. async (error: AxiosError) => {}
  5. )
  6. // 也可以直接剥离我管的数据,只返回必要的data内容
  7. instance.interceptors.response.use(
  8. (res: AxiosResponse<CommonData<any>>):any => {
  9. if (res.status >= 200 && res.status < 300) {
  10. if (res.data.code === 0) {
  11. return res.data.data
  12. }
  13. return res
  14. // res = res.data
  15. // if ((res.data as MyData).code === 0) {
  16. // return res.data
  17. // } else if (res.data.code) { }
  18. }
  19. }
  20. )

这个经过封装的 error 对象,包含了本次失败的请求所包含的参数:
image.png

比如在我们的一个项目中,后端的现状是 请求接口只会是两种结果: status200 成功 , status401未授权。根据要求,我们需要在返回401时候请求接口更新token。(这种情况并不常见,但也是一种需求。)

这里就利用 error.config 对象,重新发出了请求。

image.png

后面讲源码时候会有进一步的补充。

结合 ts

ts中有一些类型比较常用:

  • AxiosInstance 对实例进行包装
  • AxiosError 包装了axios的自定义错误类型
  • AxiosResponse 包装了返回结果,我们一般只对 data 感兴趣
  • AxiosPromise 对上面 AxiosPromise 进行了Promise进行了包装,实际中更常用

源码

axios 基于 xhr实现,这部分细节可以参考我的博客 https://www.yuque.com/xinbao37/roadmap/js-web-api.md

  • class Axios
  • 自己new,然后到处实例
  1. class Axios {
  2. get(url){
  3. let xhr = new XHR()
  4. xhr.open('get', url, true)
  5. xhr.send()
  6. }
  7. }
  • 实现 then,返回的是 promise
  • 包装 data status statusText
  • 实现可选 get options,利用 constructor

深拷贝考虑 undefined,考虑function,常见类型问题不大

默认参数和自定义参数,要考虑 merge,注意覆盖和新增

mergeConfig

interceptors 拦截器,如果request有两个 use,会先执行下面的。

参考资料