Axios你可能不知道使用方式

Posted javamianshi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Axios你可能不知道使用方式相关的知识,希望对你有一定的参考价值。

 

在前端日常开发中除了纯静态展示页面,必不可少的就是做一些接口请求,从XMLHttpRequest,到jQueryajax,再到后来的FetchAxios

为什么选择Axios

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

为什么不用Fetch

  • fetchtch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
  • fetch默认不会带cookie,需要添加配置项(Axios也需要)
  • fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行
  • fetch没有办法原生监测请求的进度

基本配置

安装

# npm
$ npm install axios
# yarn
$ yarn add axios
# cdn
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
复制代码

直接使用

1、使用.执行某个请求方法,[method name]包含了requestheadgetputdeletepostpatch

axios[method name](url[, data[, config]])
复制代码

2、使用传入config对象的方式调用

axios([config])
.then(response => response)
.catch(error => error)

// config 可选内容的配置选项。只有 url 是必需的。如果没有指定 method,请求将默认使用 get 方法。
{
  // `url` 是用于请求的服务器 URL
  url: ‘/user‘,

  // `method` 是创建请求时使用的方法
  method: ‘get‘, // 默认是 get

  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: ‘https://some-domain.com/api/‘,
  
  // `headers` 是即将被发送的自定义请求头
  headers: {‘X-Requested-With‘: ‘XMLHttpRequest‘},

  // `params` 是即将与请求一起发送的 URL 参数
  // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  params: {
    ID: 12345
  },
  ...,
  // `cancelToken` 指定用于取消请求的 cancel token
  // (查看后面的 Cancellation 这节了解更多)
  cancelToken: new CancelToken(function (cancel) {
  })
复制代码
  • 更多配置项请移步Axios官网,官网配置

3、并发处理

axios.all(iterable)
axios.spread(callback)

function getUserAccount() {
  return axios.get(‘/user/12345‘);
}

function getUserPermissions() {
  return axios.get(‘/user/12345/permissions‘);
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求都执行完成
  }));
复制代码

创建实例使用

  • 通过axios.create创建请求实例,可接收一个config对象;
import axios from axios;
var instance = axios.create([config]);
复制代码

默认config配置

1、配置请求超时时间

# 使用defaults
axios.defaults.timeout = 30000 // 时间以毫秒为单位
# 使用实例传入config
var instance = axios.create({
    timeout: 30000 
});
复制代码

2、配置请求携带cookie

# 使用defaults
axios.defaults.withCredentials = true // true为自动携带
# 使用实例传入config
var instance = axios.create({
    withCredentials: true
});
复制代码

3、配置baseURL

  • baseURL 将自动加在 url 前面,除非 url 是一个绝对 URL。
# 使用defaults
axios.defaults.baseURL = ‘https://github.com/detanx‘
# 使用实例传入config
var instance = axios.create({
    baseURL: ‘https://github.com/detanx‘
});
复制代码

4、配置headers

  • 例如设置token
# 使用defaults
axios.defaults.headers.common[‘Authorization‘] = AUTH_TOKEN;
axios.defaults.headers.post[‘Content-Type‘] = ‘application/x-www-form-urlencoded‘;
# 使用实例传入config
var instance = axios.create({
    headers: {
    ‘Content-Type‘: ‘application/x-www-form-urlencoded‘,
    ‘Authorization‘: AUTH_TOKEN
});
复制代码

5、取消请求cancelToken

  • (1)使用 CancelToken.source 工厂方法创建 cancelToken
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get(url, {
  cancelToken: source.token
}).catch(thrown => thrown);

// 取消请求(message 参数是可选的)
source.cancel(‘cancel.‘);
复制代码
  • (2)通过传递一个executor函数到CancelToken的构造函数来创建 cancelToken
const CancelToken = axios.CancelToken;
let cancel;

axios.get(url, {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函数接收一个 cancel 函数作为参数
    cancel = c;
  })
})

// 取消请求(message 参数是可选的)
cancel(‘cancel.‘);
复制代码

6、更多

拦截器配置及错误处理

  • 在请求或响应被thencatch处理前拦截它们。

请求拦截

  • 你可以直接添加到import进来的axios上面,一般建议新建Axios实例,将默认值及拦截器挂载到实例上。
const NotCancleUrl = [‘/stockserver/user/login-user‘]; // 不取消重复请求的url列表
const pendingRequestArray = []; // 声明一个数组用于存储每个请求的取消函数和请求标识
const { CancelToken } = axios;
const removePending = config => {
  for (const index in pendingRequestArray) {
    const key = `${config.url}&${config.method}`;
    if (pendingRequestArray[index].key === key && !NotCancleUrl.includes(config.url)) {
      // 当当前请求在数组中存在时执行函数体
      pendingRequestArray[index].cancel(); // 执行取消操作
      pendingRequestArray.splice(index, 1); // 把这条记录从数组中移除
    }
  }
};
// 添加请求拦截器
axios.interceptors.request.use( config => {
    // 例如添加取消重复请求
    removePending(config); // 在一个发送请求前执行一下取消操作
    config.cancelToken = new CancelToken(c => {
      // 这里的请求标识是用请求地址&请求方式拼接的字符串,你可以选择其他的一些方式
      pendingRequestArray.push({ key: `${config.url}&${config.method}`, cancel: c });
    });
    return config;
  }, function (error) {
    // 处理请求错误
    return Promise.reject(error);
  });
复制代码

响应拦截

1、 上面在请求拦截中做了重复请求的拦截,如果请求成功,我们应该在请求成功后,将相应的请求从pendingRequestArray缓存请求的数组中移除。

// 添加响应拦截器
axios.interceptors.response.use(
  // 处理响应数据
  response => {
    removePending(response.config); // 请求成功后,从pendingRequestArray中移除
    return response;
  },
  // 处理响应错误
  error => {
    return Promise.reject(error);
  }
);
复制代码

2、对相应的请求超时、401403状态做同一处理(当然你也可以根据你项目中实际的应用做一些其他的处理)。

axios.interceptors.response.use(
  response => response,
  error => {
    // 服务请求超时
    if (error === undefined || error.code === ‘ECONNABORTED‘) {
      message.warning(‘服务请求超时‘);
      return Promise.reject(error);
    }
    const {
      response: { status }
    } = error;
    const { response } = error;
    const info = response.data;
    // 401未登录
    if (status === 401) {
      // 未登录去重定向登录页面
      ...
    }
    // 403访问被拒
    if (status === 403) {
      ...
    }
    return Promise.reject(error);
  }
)
复制代码

错误处理

1、在请求的catch方法中处理

axios.get(url)
  .catch(function (error) {
    if (error.response) {
      const { data, status, headers } = error.response;
      // 请求已发出,但服务器响应的状态码不在 2xx 范围内
      console.log(data, status, headers);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log(‘Error‘, error.message);
    }
    console.log(error.config);
  });
复制代码

2、使用validateStatus配置选项定义一个自定义HTTP状态码的错误范围。

axios.get(url), {
  validateStatus: function (status) {
    return status < 500; // 状态码在大于或等于500时才会 reject
  }
})
复制代码

项目中应用

  • 默认设置及拦截器在之前已讲过,下面就只说请求方法实例封装。

通用使用封装

// 请求方法
export const AXIOS_METHOD_TYPET = {
  GET: ‘GET‘,
  POST: ‘POST‘,
  PUT: ‘PUT‘,
  DELETE: ‘DELETE‘,
  PATCH: ‘PATCH‘
};
/** 方法说明
 * @method request
 * @param api 请求相对地址
 * @param method 请求方法,默认get
 * @param params 请求参数 默认为空
 * @param config 请求配置 默认为空
 * @return function 返回axios实例
*/
const request = (api, method = AXIOS_METHOD_TYPET.GET, params = {}, config = {}) => {
    method = method.toLocaleUpperCase();
    // get请求放在params中,其他请求放在body
    const data = method === ‘GET‘ ? ‘params‘ : ‘data‘;
    // 这部分也可以放到defaults中去设置
    let headers = {
        ‘X-Requested-With‘: ‘XMLHttpRequest‘,
        ‘Content-Type‘: ‘application/json‘
    };
    if (config.headers) {
        headers = {
          ...headers,
          ...config.headers
        };
    }
    return axios({
        url: api,
        method,
        [data]: params,
        headers
    });
};
export default request;
复制代码

使用方式

// index.js
import request from ‘request‘;
request(‘/user/login‘, post, {
    username: ‘detanx‘,
    password: ‘123456‘
}).then(response => console.log(response))
.catch(error => console.log(error))
复制代码

hooks调用封装

// useRequest.js
import { useState, useEffect } from ‘react‘;
// instance 为myAxios中暴露的添加了默认方法及拦截器的axios实例
import { instance, AXIOS_METHOD_TYPET } from ‘./myAxios‘;

/** 方法说明
 * @method useRequest
 * @return [
        responseData, // 请求成功的返回
        errorData, // 请求失败返回
        loading, // 请求是否完成
        setRequestParams // 参数改变重新请求
    ] 
*/
const useRequest = (url, method = AXIOS_METHOD_TYPET.GET, params = {}, config = {}) => {
    method = method.toLocaleUpperCase();
    const data = method === ‘GET‘ ? ‘params‘ : ‘data‘;
    const [responseData, setResponseData] = useState({});
    const [errorData, setErrorData] = useState({});
    const [loading, setLoading] = useState(true);
    const [requestParams, setRequestParams] = useState(params);
    let headers = {
        ‘X-Requested-With‘: ‘XMLHttpRequest‘,
        ‘Content-Type‘: ‘application/json‘
    };
    if (config.headers) {
        headers = {
            ...headers,
            ...config.headers
        };
    }
    useEffect(() => {
        instance({
            url,
            method,
            [data]: requestParams,
            headers
        })
            .then(({ data }) => {
                setLoading(false);
                setResponseData(data);
            })
            .catch(err => {
                setLoading(false);
                setErrorData(err);
            });
    }, [requestParams]);
    return [
        responseData,
        errorData,
        loading,
        setRequestParams
    ];
};
export default useRequest;
复制代码

使用方式

// index.js
import useRequest from ‘useRequest‘;
expoert default () => {
    const [
        responseData,
        errorData,
        loading,
        setRequestParams
    ] = useRequest(‘/api/user‘, ‘get‘)
    const clickHandle = () => {
        setRequestParams({name: ‘detanx‘})
    }
    return (<>
        <button onClick={clickHandle}>新参数请求</button>
    </>)
}

hooks封装完善

  • 上面的封装会存在一个问题,就是每次使用useRequest都会直接发起一个请求,有些页面进来其实不需要请求,例如纯登录页面,只需要在提交登录信息时才需要发起请求,所以对上面的封装进行优化。约定paramsfalse不发起请求。
// 修改params的默认值为false及默认不发送请求
const useRequest = (url, method = AXIOS_METHOD_TYPET.GET, params = false, config = {}) => {
    ...
    useEffect(() => {
        // 约定`params`为`false`不发起请求
+       if (requestParams === false) return;        
        instance()
    }, [requestParams]);
    ...
};

https://weibo.com/ttarticle/p/show?id=2309404499443872301253

以上是关于Axios你可能不知道使用方式的主要内容,如果未能解决你的问题,请参考以下文章

你可能不知道的JavaScript代码片段和技巧(上)

10 个你可能还不知道 VS Code 使用技巧

10 个你可能还不知道 VS Code 使用技巧(超实用!)

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装