网络请求 之 axios

网络请求 之 axios_第1张图片

一、axios

1. 功能

axios相比浏览器提供的fetch,有更多的优点 : 

  • 在浏览器中发送 XMLHttpRequests 请求
  • 在 node.js 中发送 http请求
  • 支持 Promise AP
  • 拦截请求和响应 ( 原生fetch需要自己手动封装,比较麻烦 )
  • 转换请求和响应数据
  • ......

2. 安装

npm i axios

3. 常见的配置选项

网络请求 之 axios_第2张图片

4. 请求方式

01 - axios

axios(config)

import axios from 'axios';

axios({
  // 请求方式
  method: 'get',
  // 请求地址
  url: 'http:......'
}).then((res) => {
  // 会返回一个promise,可以通过.then拿到结果
  console.log('res', res.data);
});

02 - request

axios.request(config)

import axios from 'axios';

axios.request({
  // 请求方式
  method: 'get',
  // 请求地址
  url: 'http:......'
}).then((res) => {
  // 会返回一个promise,可以通过.then拿到结果
  console.log('res', res.data);
});

03 - get

axios.get(url[, config])

ps :  一样用法

axios.delete(url[, config])

axios.head(url[, config])

// 1. 可以在地址栏上直接跟上参数
axios.get('http://xxxxxx?id=123&name=coder').then((res) => {
  console.log('res', res.data);
});

axios
  .get('http://xxxxxx', {
    // 2. 参数写在这里
    params: {
      id: 123,
      name: 'coder'
    }
  })
  .then((res) => {
    console.log('res', res.data);
  });

04 - post

axios.post(url[, data[, config]])

 

ps : 一样用法

axios.put(url[, data[, config]])

axios.patch(url[, data[, config]])

import axios from 'axios';

axios
  .post('http:xxxxxx', {
    // 1. 把传递的参数直接写在这里
    name: 'coder',
    age: 18
  })
  .then((res) => {
    console.log('res', res.data);
  });

axios
  .post('http:xxxxxx', {
    // 2. 参数写在这里
    data: {
      name: 'star',
      age: 16
    }
  })
  .then((res) => {
    console.log('res', res.data);
  });

5. 配置公共的基础配置

// 1.baseURL
const baseURL = "http://123.123.123.123:8000"

// 给axios实例配置公共的基础配置
axios.defaults.baseURL = baseURL
axios.defaults.timeout = 10000
axios.defaults.headers = {}

// 2.使用
axios.get("/abc/a").then(res => {
  console.log("res:", res.data)
})

// 3. 如果地址完整,就不会使用默认的配置
axios.get("http://456.456.456.456:8000/abc/a").then(res => {
  console.log("res:", res.data)
})

6. 同时发送多个请求

// 等待两个请求都完成后,才会调用then
axios.all([
  axios.get("http://123.111.222.333:9001/a"),
  axios.get("http://123.222.333.444:9001/b")
]).then(res => {
  console.log("res:", res)
})

// 底层的本质是调用了promise.all

7. axios创建实例 

创建实例的目的 : 

  • 当我们从axios模块中导入对象时, 使用的实例是默认的实例
  • 当给该实例设置一些默认配置时, 这些配置就被固定下来了
  • 但是后续开发中, 某些配置可能会不太一样
  • 比如某些请求需要使用特定的baseURL或者timeout等
  • 这个时候, 可以创建新的实例, 并且传入属于该实例的配置信息.

如果项目比较大,用的数据并不是来自同一个服务器

方式一 : 创建各个实例,配置不同的baseURL

方式二 : 配置proxy,根据相同路由名称来映射至不同的网络

// 创建实例一
const instance1 = axios.create({
  baseURL: "http://123.123.123.123:9001",
  timeout: 6000,
  headers: {}
})
// 发送网络请求
instance1.get("/abc", {
  params: {
    id: 1
  }
}).then(res => {
  console.log("res:", res.data)
})

// 创建实例二
const instance2 = axios.create({
  baseURL: "http://456.456.456.456:8000",
  timeout: 10000,
  headers: {}
})

8. axios请求和响应拦截器

01 - 请求拦截

/**
   对实例配置拦截
   这里使用默认实例
*/
axios.interceptors.request.use((config) => {
  console.log("请求成功的拦截")
  /**
    可以做
        开始loading的动画
        对原来的配置进行一些修改
        header
        认证登录: token/cookie
        请求参数进行某些转化
  */
  config.header['token'] = '123321fasdfagea'
  
  // 最后要把被指返回出去
  return config
}, (err) => {
  console.log("请求失败的拦截")
  return err
})

02 - 响应拦截

axios.interceptors.response.use((res) => {
  console.log("响应成功的拦截")

  // 1.结束loading的动画

  // 2.对数据进行转化, 再返回数据
  return res.data
}, (err) => {
  console.log("响应失败的拦截:", err)
  return err
})

二、axios - 普通版本封装

import axios from 'axios'

// 1. 创建一个类
class starRequest {
  // 2. 构造函数中配置实例的基本配置
  constructor(baseURL, timeout=10000) {
    this.instance = axios.create({
      baseURL,
      timeout
    })
  }
  // 3. 封装请求
  request(config) {
    return new Promise((resolve, reject) => {
      this.instance.request(config).then(res => {
        resolve(res.data)
      }).catch(err => {
        reject(err)
      })
    })
  }

  get(config) {
    return this.request({ ...config, method: "get" })
  }

  post(config) {
    return this.request({ ...config, method: "post" })
  }
}

// 4. 导出
export default new starRequest("http://xxxxx:9001")

三、axios - TS版本封装

网络请求 之 axios_第3张图片

1. 简洁版

config/index.ts

/**
 * 配置文件
 */
export const BASE_URL = 'http://xxx:8000'
export const TIMEOUT = 10000

request/index.ts

/**
 * 封装axios请求
 */
// 1. 引入axios,导入类型
import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig } from 'axios';

class StarRequest {
  // 实例类型 => AxiosInstance
  private instance: AxiosInstance;
  // config类型 => AxiosRequestConfig
  constructor(config: AxiosRequestConfig) {
    // 2. 创建实例
    this.instance = axios.create(config);
  }

  // 3. 封装请求方法
  request(config: AxiosRequestConfig) {
    return this.instance.request(config);
  }
  get() {}
  post() {}
}

export default StarRequest;

 modules/home.ts

/**
 * home模块: 用于存放home模块的接口
 */
import starRequest from '..';

export const getHomeData = () => {
  return starRequest.request({
    url: '/home/multidata'
  });
};

index.ts

/**
 * 统一的出口文件,方便其他地方引入
 */
import { BASE_URL, TIMEOUT } from './config';
import StarRequest from './request';

// 导出实例
const starRequest = new StarRequest({
  baseURL: BASE_URL,
  timeout: TIMEOUT
});
export default starRequest;

// 导出请求方法
export * from './modules/home';

使用

import { getHomeData } from './service';
getHomeData().then((res) => {
  console.log(res.data);
});

网络请求 之 axios_第4张图片

2. 增加拦截器 

全局拦截器 : 直接往instance上增加,每个请求都会触发

指定实例拦截器 : 给单独的实例再次增加拦截

 

ps : 拦截器可重复设置,不会覆盖

  • 需求 : 给部分接口请求增加特定拦截
  • 1. 给AxiosRequestConfig进行扩展
  • 2. 实例创建的时候传递拦截
  • 3. 构造函数中判断,增加新拦截

config/index.ts

/**
 * 配置文件
 */
// 普通接口
export const BASE_URL = 'http://xxx:1111'
// 需要拦截的接口
export const BASE_URL2 = 'http://yyyyyy:2222/api'

export const TIMEOUT = 10000

request/type.ts

import { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';

// 类型扩展,继承axios的类型,添加自定义的拦截器
export interface StarRequestConfig extends AxiosRequestConfig {
  // 设置自定义的拦截器,可选
  interceptors?: {
    requestSuccessFn?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
    requestFailureFn?: (err: any) => any;
    responseSuccessFn?: (res: AxiosResponse) => AxiosResponse;
    responseFailureFn?: (err: any) => any;
  };
}

request/index.ts

/**
 * 封装axios请求
 */
import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig } from 'axios';
// 1. 导入自定义扩展的类型,增加拦截器的可选参数
import type { StarRequestConfig } from './type';

class StarRequest {
  private instance: AxiosInstance;
  constructor(config: StarRequestConfig) {
    this.instance = axios.create(config);
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config) => {
        console.log('全局请求拦截器-请求成功');

        // 添加token
        config.headers.token = 'token666';
        return config;
      },
      (err) => {
        console.log('全局请求拦截器-请求失败');
        return err;
      }
    );
    // 响应拦截器
    this.instance.interceptors.response.use(
      (res) => {
        console.log('全局响应拦截器-响应成功');
        return res.data;
      },
      (err) => {
        console.log('全局响应拦截器-响应失败');
        return err;
      }
    );

    // 2. 针对特定的实例,添加拦截器 => 使用?可选链
    this.instance.interceptors.request.use(
      config.interceptors?.requestSuccessFn,
      config.interceptors?.requestFailureFn
    );
    this.instance.interceptors.response.use(
      config.interceptors?.responseSuccessFn,
      config.interceptors?.responseFailureFn
    );
  }

  request(config: AxiosRequestConfig) {
    return this.instance.request(config);
  }
  get() {}
  post() {}
}

export default StarRequest;

 modules/extire.ts

import { starRequest2 } from '../index';

export const getEntiryList = () => {
  return starRequest2.request({
    url: '/entire/list',
    params: {
      offset: 0,
      size: 20
    }
  });
};

index.ts

/**
 * 统一的出口文件,方便其他地方引入
 */
import { BASE_URL, BASE_URL2, TIMEOUT } from './config';
import StarRequest from './request';

// 导出请求方法
export * from './modules/home';
export * from './modules/entire';

// 导出实例 => 普通接口
const starRequest = new StarRequest({
  baseURL: BASE_URL,
  timeout: TIMEOUT
});
export default starRequest;

// 导出实例2 => 添加特定拦截的接口
export const starRequest2 = new StarRequest({
  baseURL: BASE_URL2,
  timeout: TIMEOUT,
  interceptors: {
    requestSuccessFn: (config) => {
      console.log('实例2请求拦截 - 请求成功');
      return config;
    },
    requestFailureFn: (err) => {
      console.log('实例2请求拦截 - 请求失败');
      return err;
    },
    responseSuccessFn: (res) => {
      console.log('实例2响应拦截 - 响应成功');
      return res;
    },
    responseFailureFn: (err) => {
      console.log('实例2响应拦截 - 响应失败');
      return err;
    }
  }
});

使用

import { getHomeData, getEntiryList } from './service';

// 普通接口请求
getHomeData().then((res) => {
  console.log(res);
});

// 特定拦截的接口请求
getEntiryList().then((res) => {
  console.log(res);
});

网络请求 之 axios_第5张图片

3. 给返回数据加上类型

网络请求 之 axios_第6张图片

modules/home.ts

/**
 * home模块: 用于存放home模块的接口
 */
import starRequest from '..';

// 1. 定义接口
interface IHomeData {
  data: any;
  returnCode: string;
  success: boolean;
}

export const getHomeData = () => {
  // 2. 使用泛型, 指定返回值类型
  return starRequest.request({
    url: '/home/multidata'
  });
};

modules/entire.ts

import { starRequest2 } from '../index';

// 1. 定义接口
interface IEntireList {
  list: any[];
  errorCode: number;
  totalCount: number;
}

export const getEntiryList = () => {
  // 2. 使用泛型, 指定返回值类型
  return starRequest2.request({
    url: '/entire/list',
    params: {
      offset: 0,
      size: 20
    }
  });
};

request/index.ts

网络请求 之 axios_第7张图片

  /**
   * 重载request方法,增加泛型, 用于指定返回值类型
   * 注意是传入第二个泛型R,而不是第一个泛型T
   * 默认泛型T为any,如果不指定,返回值类型为unknown => 无法使用
   */
  request(config: AxiosRequestConfig) {
    return this.instance.request(config);
  }

  get(config: AxiosRequestConfig) {
    return this.instance.request({ ...config, method: 'GET' });
  }
  post(config: AxiosRequestConfig) {
    return this.instance.request({ ...config, method: 'POST' });
  }
  delete(config: AxiosRequestConfig) {
    return this.instance.request({ ...config, method: 'DELETE' });
  }
  patch(config: AxiosRequestConfig) {
    return this.instance.request({ ...config, method: 'PATCH' });
  }

效果

网络请求 之 axios_第8张图片

总结难点

  • 拦截器控制
    • 全局拦截器
    • 实例拦截器
  • 响应结果类型处理
    • ​​​​​​​泛型

 

你可能感兴趣的:(随笔,前端,javascript,http,axios)