进阶Axios:从入门到实践,构建高效HTTP请求

1. Axios 概述

Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。它具有以下特点:

  • 支持浏览器和 Node.js 环境
  • 支持 Promise API
  • 可以拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换 JSON 数据

2. Axios 的基本使用

发送 GET 请求

axios.get('https://api.example.com/data')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
axios.get('https://api.example.com/data')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });
axios.get('https://api.example.com/data') .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });

发送 POST 请求

axios.post('https://api.example.com/submit', {
key: 'value'
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
axios.post('https://api.example.com/submit', {
  key: 'value'
})
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });
axios.post('https://api.example.com/submit', { key: 'value' }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });

3. Axios 配置选项

你可以通过配置对象来调整请求的行为:

axios({
method: 'post',
url: 'https://api.example.com/submit',
data: {
key: 'value'
},
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
axios({
  method: 'post',
  url: 'https://api.example.com/submit',
  data: {
    key: 'value'
  },
  headers: {
    'Content-Type': 'application/json'
  }
})
.then(response => {
  console.log(response.data);
})
.catch(error => {
  console.error(error);
});
axios({ method: 'post', url: 'https://api.example.com/submit', data: { key: 'value' }, headers: { 'Content-Type': 'application/json' } }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });

4. 创建 Axios 实例

可以创建预配置的 Axios 实例:

const instance = axios.create({
baseURL: 'https://api.example.com',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 1000,
  headers: {'X-Custom-Header': 'foobar'}
});
const instance = axios.create({ baseURL: 'https://api.example.com', timeout: 1000, headers: {'X-Custom-Header': 'foobar'} });

5. 请求和响应拦截器

请求拦截器

axios.interceptors.request.use(
function(config) {
// 在发送请求之前做一些事情
return config;
},
function(error) {
// 处理请求错误
return Promise.reject(error);
}
);
axios.interceptors.request.use(
  function(config) {
    // 在发送请求之前做一些事情
    return config;
  },
  function(error) {
    // 处理请求错误
    return Promise.reject(error);
  }
);
axios.interceptors.request.use( function(config) { // 在发送请求之前做一些事情 return config; }, function(error) { // 处理请求错误 return Promise.reject(error); } );

响应拦截器

axios.interceptors.response.use(
function(response) {
// 对响应数据做点什么
return response;
},
function(error) {
// 对响应错误做点什么
return Promise.reject(error);
}
);
axios.interceptors.response.use(
  function(response) {
    // 对响应数据做点什么
    return response;
  },
  function(error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);
axios.interceptors.response.use( function(response) { // 对响应数据做点什么 return response; }, function(error) { // 对响应错误做点什么 return Promise.reject(error); } );

6. 错误处理

当使用 Axios 发送请求时,如果请求失败,Promise 将会被 reject,并且可以在 .catch() 块中捕获这个错误。下面是一个具体的示例:

axios.get('https://api.example.com/data')
.then(response => {
console.log('Data received:', response.data);
})
.catch(error => {
console.error('An error occurred:', error);
// 你可以检查错误的不同属性来确定错误的类型
if (error.response) {
// 请求已发出,服务器也响应了状态码,但状态码不在 2xx 范围内
console.log('Server responded with a status of:', error.response.status);
console.log('Response data:', error.response.data);
} else if (error.request) {
// 请求已发出,但没有收到响应
console.log('No response received:', error.request);
} else {
// 设置请求时发生了错误
console.log('Error setting up the request:', error.message);
}
console.log('Error config:', error.config);
});
axios.get('https://api.example.com/data')
  .then(response => {
    console.log('Data received:', response.data);
  })
  .catch(error => {
    console.error('An error occurred:', error);

    // 你可以检查错误的不同属性来确定错误的类型
    if (error.response) {
      // 请求已发出,服务器也响应了状态码,但状态码不在 2xx 范围内
      console.log('Server responded with a status of:', error.response.status);
      console.log('Response data:', error.response.data);
    } else if (error.request) {
      // 请求已发出,但没有收到响应
      console.log('No response received:', error.request);
    } else {
      // 设置请求时发生了错误
      console.log('Error setting up the request:', error.message);
    }
    console.log('Error config:', error.config);
  });
axios.get('https://api.example.com/data') .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); // 你可以检查错误的不同属性来确定错误的类型 if (error.response) { // 请求已发出,服务器也响应了状态码,但状态码不在 2xx 范围内 console.log('Server responded with a status of:', error.response.status); console.log('Response data:', error.response.data); } else if (error.request) { // 请求已发出,但没有收到响应 console.log('No response received:', error.request); } else { // 设置请求时发生了错误 console.log('Error setting up the request:', error.message); } console.log('Error config:', error.config); });

在这个示例中,我们向 'https://api.example.com/data' 发送了一个 GET 请求。如果请求成功,我们将接收到服务器返回的数据;但如果请求失败,.catch() 块将被触发,你可以在其中处理错误。

错误对象 error 包含了许多有用的信息,比如:

  • error.response:包含服务器的响应,如果有的话。它是一个包含 datastatusheaders 属性的对象。
  • error.request:包含创建的 XMLHttpRequest 对象,如果请求已经发出并且没有收到响应的话。
  • error.message:描述错误的字符串。
  • error.config:包含发送请求时的配置信息。

通过检查这些属性,可以更准确地定位错误原因,并采取相应的措施。例如,如果服务器返回了一个 404 错误,可能需要检查请求的 URL 是否正确;如果是 500 内部服务器错误,可能需要联系服务器管理员或开发者查看服务器日志。

7. 取消请求

可以创建一个 CancelToken 并在需要时取消请求:

const source = axios.CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(thrown => {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
// 取消请求
source.cancel('Operation canceled by the user.');
const source = axios.CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(thrown => {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

// 取消请求
source.cancel('Operation canceled by the user.');
const source = axios.CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }).catch(thrown => { if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // handle error } }); // 取消请求 source.cancel('Operation canceled by the user.');

8. 封装 Axios

封装 Axios 可以让代码更整洁,更容易管理。可以在一个模块中封装所有的请求方法:

import axios from 'axios';
const apiClient = axios.create({
baseURL: 'https://api.example.com',
timeout: 1000,
});
// 封装 GET 请求
const get = (url, params) => apiClient.get(url, { params }).then(res => res.data);
// 封装 POST 请求
const post = (url, data) => apiClient.post(url, data).then(res => res.data);
// 封装 PUT 请求
const put = (url, data) => apiClient.put(url, data).then(res => res.data);
// 封装 DELETE 请求
const del = url => apiClient.delete(url).then(res => res.data);
// 封装 PATCH 请求
const patch = (url, data) => apiClient.patch(url, data).then(res => res.data);
// 导出这些方法
export { get, post, put, del, patch };
import axios from 'axios';

const apiClient = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 1000,
});

// 封装 GET 请求
const get = (url, params) => apiClient.get(url, { params }).then(res => res.data);

// 封装 POST 请求
const post = (url, data) => apiClient.post(url, data).then(res => res.data);

// 封装 PUT 请求
const put = (url, data) => apiClient.put(url, data).then(res => res.data);

// 封装 DELETE 请求
const del = url => apiClient.delete(url).then(res => res.data);

// 封装 PATCH 请求
const patch = (url, data) => apiClient.patch(url, data).then(res => res.data);

// 导出这些方法
export { get, post, put, del, patch };
import axios from 'axios'; const apiClient = axios.create({ baseURL: 'https://api.example.com', timeout: 1000, }); // 封装 GET 请求 const get = (url, params) => apiClient.get(url, { params }).then(res => res.data); // 封装 POST 请求 const post = (url, data) => apiClient.post(url, data).then(res => res.data); // 封装 PUT 请求 const put = (url, data) => apiClient.put(url, data).then(res => res.data); // 封装 DELETE 请求 const del = url => apiClient.delete(url).then(res => res.data); // 封装 PATCH 请求 const patch = (url, data) => apiClient.patch(url, data).then(res => res.data); // 导出这些方法 export { get, post, put, del, patch };

9. 高级用法

高级请求通常涉及更复杂的场景,例如处理大量并发请求、错误重试、请求取消、请求和响应的转换、自定义请求和响应拦截器等。下面我将通过一些具体的例子来展示这些高级用法。

1. 并发请求

当需要同时发送多个请求并等待所有请求完成时,可以使用 Promise.all 或者 axios.all 方法:

axios.all([
axios.get('https://api.example.com/users'),
axios.get('https://api.example.com/posts')
])
.then(axios.spread((usersResponse, postsResponse) => {
console.log(usersResponse.data);
console.log(postsResponse.data);
}))
.catch(errors => {
console.error(errors);
});
axios.all([
  axios.get('https://api.example.com/users'),
  axios.get('https://api.example.com/posts')
])
.then(axios.spread((usersResponse, postsResponse) => {
  console.log(usersResponse.data);
  console.log(postsResponse.data);
}))
.catch(errors => {
  console.error(errors);
});
axios.all([ axios.get('https://api.example.com/users'), axios.get('https://api.example.com/posts') ]) .then(axios.spread((usersResponse, postsResponse) => { console.log(usersResponse.data); console.log(postsResponse.data); })) .catch(errors => { console.error(errors); });

2. 错误重试

在某些情况下,可能需要在请求失败后自动重试。这可以通过使用中间件或自定义拦截器来实现:

const retryInterceptor = axios.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const response = await axios.post('/auth/token');
const token = response.data.token;
originalRequest.headers['Authorization'] = `Bearer ${token}`;
return axios(originalRequest);
} catch (_error) {
return Promise.reject(_error);
}
}
return Promise.reject(error);
}
);
const retryInterceptor = axios.interceptors.response.use(
  response => response,
  async error => {
    const originalRequest = error.config;

    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;

      try {
        const response = await axios.post('/auth/token');
        const token = response.data.token;
        originalRequest.headers['Authorization'] = `Bearer ${token}`;

        return axios(originalRequest);
      } catch (_error) {
        return Promise.reject(_error);
      }
    }

    return Promise.reject(error);
  }
);
const retryInterceptor = axios.interceptors.response.use( response => response, async error => { const originalRequest = error.config; if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { const response = await axios.post('/auth/token'); const token = response.data.token; originalRequest.headers['Authorization'] = `Bearer ${token}`; return axios(originalRequest); } catch (_error) { return Promise.reject(_error); } } return Promise.reject(error); } );

3. 请求取消

在某些情况下,可能需要在请求发送后取消它。这可以通过 CancelToken 来实现:

const source = axios.CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
})
.then(response => {
console.log(response.data);
})
.catch(throwError => {
if (axios.isCancel(throwError)) {
console.log('Request canceled', throwError.message);
} else {
console.error('A request failed:', throwError);
}
});
// 后面的某个时刻,取消请求
source.cancel('Operation canceled by the user.');
const source = axios.CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
})
.then(response => {
  console.log(response.data);
})
.catch(throwError => {
  if (axios.isCancel(throwError)) {
    console.log('Request canceled', throwError.message);
  } else {
    console.error('A request failed:', throwError);
  }
});

// 后面的某个时刻,取消请求
source.cancel('Operation canceled by the user.');
const source = axios.CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }) .then(response => { console.log(response.data); }) .catch(throwError => { if (axios.isCancel(throwError)) { console.log('Request canceled', throwError.message); } else { console.error('A request failed:', throwError); } }); // 后面的某个时刻,取消请求 source.cancel('Operation canceled by the user.');

4. 请求和响应转换

可能需要在发送请求或接收到响应之前转换数据,例如序列化或反序列化数据:

axios({
url: '/foo',
method: 'post',
data: { bar: 'baz' },
transformRequest: [function(data) {
// 将请求数据转换成字符串
return JSON.stringify({ ...data });
}],
transformResponse: [function(data) {
// 将响应数据转换成 JSON 对象
return JSON.parse(data);
}]
})
.then(response => {
console.log(response.data);
});
axios({
  url: '/foo',
  method: 'post',
  data: { bar: 'baz' },
  transformRequest: [function(data) {
    // 将请求数据转换成字符串
    return JSON.stringify({ ...data });
  }],
  transformResponse: [function(data) {
    // 将响应数据转换成 JSON 对象
    return JSON.parse(data);
  }]
})
.then(response => {
  console.log(response.data);
});
axios({ url: '/foo', method: 'post', data: { bar: 'baz' }, transformRequest: [function(data) { // 将请求数据转换成字符串 return JSON.stringify({ ...data }); }], transformResponse: [function(data) { // 将响应数据转换成 JSON 对象 return JSON.parse(data); }] }) .then(response => { console.log(response.data); });

5. 自定义请求和响应拦截器

拦截器允许在请求被发送或响应被处理之前修改它们:

axios.interceptors.request.use(request => {
// 在请求发送之前做一些事情
console.log('Sending request:', request);
return request;
}, error => {
// 处理请求错误
return Promise.reject(error);
});
axios.interceptors.response.use(response => {
// 在响应被传递给 then 前做一些事情
console.log('Received response:', response);
return response;
}, error => {
// 处理响应错误
return Promise.reject(error);
});
axios.interceptors.request.use(request => {
  // 在请求发送之前做一些事情
  console.log('Sending request:', request);
  return request;
}, error => {
  // 处理请求错误
  return Promise.reject(error);
});

axios.interceptors.response.use(response => {
  // 在响应被传递给 then 前做一些事情
  console.log('Received response:', response);
  return response;
}, error => {
  // 处理响应错误
  return Promise.reject(error);
});
axios.interceptors.request.use(request => { // 在请求发送之前做一些事情 console.log('Sending request:', request); return request; }, error => { // 处理请求错误 return Promise.reject(error); }); axios.interceptors.response.use(response => { // 在响应被传递给 then 前做一些事情 console.log('Received response:', response); return response; }, error => { // 处理响应错误 return Promise.reject(error); });

通过这些高级功能,可以根据不同的需求定制 Axios 的行为,以满足复杂的应用场景。在实际开发中,结合业务需求选择合适的策略是非常重要的。

10. 性能优化

使用缓存、优化请求头和压缩技术是提高网络请求效率和性能的重要手段。下面将针对这三点给出具体的示例。

1. 使用缓存机制

示例: 使用 axios-cache-adapter 库来缓存响应,减少不必要的网络请求。

首先,需要安装 axios-cache-adapter

npm install axios-cache-adapter
npm install axios-cache-adapter
npm install axios-cache-adapter

然后,在代码中使用它:

import axios from 'axios';
import CacheAdapter from 'axios-cache-adapter';
const cache = new CacheAdapter({
maxAge: 60 * 1000, // 缓存有效期为1分钟
});
const cachedAxios = axios.create({
adapter: cache.adapter,
});
// 发送请求,如果缓存中有数据则不会再次请求
cachedAxios.get('https://api.example.com/data')
.then(response => {
console.log('Data received:', response.data);
})
.catch(error => {
console.error('An error occurred:', error);
});
import axios from 'axios';
import CacheAdapter from 'axios-cache-adapter';

const cache = new CacheAdapter({
  maxAge: 60 * 1000, // 缓存有效期为1分钟
});

const cachedAxios = axios.create({
  adapter: cache.adapter,
});

// 发送请求,如果缓存中有数据则不会再次请求
cachedAxios.get('https://api.example.com/data')
  .then(response => {
    console.log('Data received:', response.data);
  })
  .catch(error => {
    console.error('An error occurred:', error);
  });
import axios from 'axios'; import CacheAdapter from 'axios-cache-adapter'; const cache = new CacheAdapter({ maxAge: 60 * 1000, // 缓存有效期为1分钟 }); const cachedAxios = axios.create({ adapter: cache.adapter, }); // 发送请求,如果缓存中有数据则不会再次请求 cachedAxios.get('https://api.example.com/data') .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); });

2. 优化请求头

示例: 仅在需要时发送特定的请求头,例如 If-None-MatchIf-Modified-Since,以利用 HTTP 的条件请求。

import axios from 'axios';
let lastModified;
axios.get('https://api.example.com/data', {
headers: {
'If-Modified-Since': lastModified,
},
})
.then(response => {
console.log('Data received:', response.data);
lastModified = response.headers['last-modified'];
})
.catch(error => {
if (error.response && error.response.status === 304) {
console.log('Data has not been modified since the last request');
} else {
console.error('An error occurred:', error);
}
});
import axios from 'axios';

let lastModified;

axios.get('https://api.example.com/data', {
  headers: {
    'If-Modified-Since': lastModified,
  },
})
.then(response => {
  console.log('Data received:', response.data);
  lastModified = response.headers['last-modified'];
})
.catch(error => {
  if (error.response && error.response.status === 304) {
    console.log('Data has not been modified since the last request');
  } else {
    console.error('An error occurred:', error);
  }
});
import axios from 'axios'; let lastModified; axios.get('https://api.example.com/data', { headers: { 'If-Modified-Since': lastModified, }, }) .then(response => { console.log('Data received:', response.data); lastModified = response.headers['last-modified']; }) .catch(error => { if (error.response && error.response.status === 304) { console.log('Data has not been modified since the last request'); } else { console.error('An error occurred:', error); } });

在这个例子中,如果服务器的数据没有改变,它会返回一个 304 Not Modified 的状态码,客户端就可以使用缓存中的数据,而无需下载新的数据。

3. 使用压缩技术

示例: 通过设置 Accept-Encoding 请求头来请求压缩的数据。

import axios from 'axios';
axios.get('https://api.example.com/data', {
headers: {
'Accept-Encoding': 'gzip, deflate, br', // 支持 gzip, deflate 和 Brotli 压缩
},
})
.then(response => {
console.log('Data received:', response.data);
})
.catch(error => {
console.error('An error occurred:', error);
});
import axios from 'axios';

axios.get('https://api.example.com/data', {
  headers: {
    'Accept-Encoding': 'gzip, deflate, br', // 支持 gzip, deflate 和 Brotli 压缩
  },
})
.then(response => {
  console.log('Data received:', response.data);
})
.catch(error => {
  console.error('An error occurred:', error);
});
import axios from 'axios'; axios.get('https://api.example.com/data', { headers: { 'Accept-Encoding': 'gzip, deflate, br', // 支持 gzip, deflate 和 Brotli 压缩 }, }) .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); });

服务器如果支持压缩,会根据请求头中的 Accept-Encoding 字段来选择合适的压缩算法对响应体进行压缩,从而减少传输数据的大小,加快响应速度。

通过实施这些策略,可以显著提升应用的性能,减少用户的等待时间,同时降低服务器的带宽消耗。

结语

通过以上讲解,应该对 Axios 有了较为全面的理解。实践是检验学习成果的最佳方式,尝试在项目中应用 Axios,并不断探索其更多高级功能,会逐渐成为 Axios 的高手。如果遇到具体问题,查阅官方文档或寻求社区帮助都是很好的解决途径。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
anything that adds laughter and joy to your life.
不要延迟任何可以给你的生活带来欢笑与快乐的事情
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容