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