如何使用axios发出高大上的HTTP请求

5,201 阅读8分钟

翻译:Da
原文地址:blog.logrocket.com/how-to-make…

对前端工程师来说,跟服务器交流的最通用方式就是Http协议,我们比较熟悉的发送请求的方式有Fetch API和XMLHttpRequest。下面我们会全面的介绍Axios —— 一个基于浏览器内置的XMLHttpRequest接口的HTTP API库,看看是哪些优秀的功能让它在前端开发者中越来越流行。

选择Axios的原因

跟Fetch一样,Axios也是基于Promise的。但是,它提供了更强大,更灵活的特性配置。以下是相对于原生Fetch API的优点。

  • 可以拦截请求和响应
  • 简化错误处理
  • XSRF防御
  • 支持上传进度
  • 支持响应超时
  • 支持请求取消
  • 支持旧版本浏览器
  • 自动转换JSON数据

安装

你可以使用以下方法安装

  • npm:
$ npm install axios
  • bower:
$ bower install axios
  • 引入脚本
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

发送请求

在axios中,发送请求是非常简单的,只需要将配置对象传给Axios函数即可,url属性是必填的;method默认为get。下面来看一个简单的例子

// send a POST request
axios({
  method: 'post',
  url: '/login',
  data: {
    firstName: 'Finn',
    lastName: 'Williams'
  }
});

用过JQuery的同学应该看着挺眼熟的,它的用法很像$.ajax。上面的代码实现了发送Post请求到/login,并携带一个对象作为参数,Axios会自动将参数转换为JSON格式,将其作为请求正文发送。

方法速记

Axios同样提供了一系列的速记方法,用来执行不同类型的请求。

  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.head(url[, config])
  • axios.options(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])
  • axios.patch(url[, data[, config]])

举例如下,以下代码展示了前面的例子怎么用axios.post重写:

axios.post('/login', {
  firstName: 'Finn',
  lastName: 'Williams'
});

处理响应

一旦HTTP请求发起,Axios就会返回一个Promise对象(fulfilled或rejected,取决于后端服务的响应),我们可以使用then()处理返回的结果,如下:

axios.post('/login', {
  firstName: 'Finn',
  lastName: 'Williams'
})
.then((response) => {
  console.log(response);
}, (error) => {
  console.log(error);
});

如果返回的promise是fulfilled的,那么作为then()第一个参数的函数将会被执行;若promise是rejected的,作为第二个参数的函数会被执行。根据文档所述,fulfilled状态的value包含以下内容:

{
  // `data` is the response that was provided by the server
  data: {},
 
  // `status` is the HTTP status code from the server response
  status: 200,
 
  // `statusText` is the HTTP status message from the server response
  statusText: 'OK',
 
  // `headers` the headers that the server responded with
  // All header names are lower cased
  headers: {},
 
  // `config` is the config that was provided to `axios` for the request
  config: {},
 
  // `request` is the request that generated this response
  // It is the last ClientRequest instance in node.js (in redirects)
  // and an XMLHttpRequest instance the browser
  request: {}
}

下面我们以向一个GitHub API发送请求为例,看看它的返回值:

axios.get('https://api.github.com/users/mapbox')
  .then((response) => {
    console.log(response.data);
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.headers);
    console.log(response.config);
  });

// logs:
// => {login: "mapbox", id: 600935, node_id: "MDEyOk9yZ2FuaXphdGlvbjYwMDkzNQ==", avatar_url: "https://avatars1.githubusercontent.com/u/600935?v=4", gravatar_id: "", …}
// => 200
// => OK
// => {x-ratelimit-limit: "60", x-github-media-type: "github.v3", x-ratelimit-remaining: "60", last-modified: "Wed, 01 Aug 2018 02:50:03 GMT", etag: "W/"3062389570cc468e0b474db27046e8c9"", …}
// => {adapter: ƒ, transformRequest: {…}, transformResponse: {…}, timeout: 0, xsrfCookieName: "XSRF-TOKEN", …}

同时发送请求

Axios有一个非常有趣的功能,他可以平行发送多个请求,通过向axios.all()方法传递数组格式的参数。这个方法会返回一个promise对象,并且当所有请求都被resolve时,它才会resolve。下面是个简单的例子:

// execute simultaneous requests 
axios.all([
  axios.get('https://api.github.com/users/mapbox'),
  axios.get('https://api.github.com/users/phantomjs')
])
.then(responseArr => {
  //this will be executed only when all requests are complete
  console.log('Date created: ', responseArr[0].data.created_at);
  console.log('Date created: ', responseArr[1].data.created_at);
});

// logs:
// => Date created:  2011-02-04T19:02:13Z
// => Date created:  2017-04-03T17:25:46Z****

以上代码向GitHub API发送了两个请求,然后打印了每个返回值的create_at属性的值。需要注意的是:如果任何一个请求的被rejected,那么该promise对象将会立即reject出第一个被reject的promise对象的结果。

为了方便,Axios同样提供了一个axios.spread()方法,分配响应数组的属性给单独的变量,下面是简单的使用方法:

axios.all([
  axios.get('https://api.github.com/users/mapbox'),
  axios.get('https://api.github.com/users/phantomjs')
])
.then(axios.spread((user1, user2) => {
  console.log('Date created: ', user1.data.created_at);
  console.log('Date created: ', user2.data.created_at);
}));

这段代码的返回值跟上段代码相同,唯一的不同就是axios.spread()方法将响应数组中的值分配给两个单独的变量了。

发送自定义的请求头

用Axios自定义请求头非常简单,只需要简单传递一个配置了请求头的对象作为最后一个参数即可,如下:

const options = {
  headers: {'X-Custom-Header': 'value'}
};

axios.post('/save', { a: 10 }, options);

转换请求和响应的格式

默认情况下,Axios自动将请求和响应的格式转换成JSON,但是它也允许你覆盖默认行为,重写定义不同的转化机制。当API只接受特殊的数据格式,像XML或CSV时,这个功能就非常有用了。

在向服务器发送请求前,在config对象中设置transformRequest属性(注意:这个方法只在PUT,POST,PATCH请求中生效),下面是使用方法:

const options = {
  method: 'post',
  url: '/login',
  data: {
    firstName: 'Finn',
    lastName: 'Williams'
  },
  transformRequest: [(data, headers) => {
    // transform the data

    return data;
  }]
};

// send the request
axios(options);

想要在触发then()或catch()之前修改响应数据的格式,你只需要设置transformResponse属性,如下:

const options = {
  method: 'post',
  url: '/login',
  data: {
    firstName: 'Finn',
    lastName: 'Williams'
  },
  transformResponse: [(data) => {
    // transform the response

    return data;
  }]
};

// send the request
axios(options);

拦截请求和响应

拦截HTTP请求是Axios很受欢迎的一个特性,通过这个特性,你可以在自己的应用程序向服务器发送请求之前检查、修改请求(反之亦然),这个方法对于各种隐性的任务(像日志或者身份验证)非常有用。

一眼看过去,拦截器的功能很像一个转换器,但是他们之间有一个非常重要的不同点:转化器只将数据和头信息作为参数接受,拦截器则是接收整个响应对象或请求配置。

你可以用以下方式声明一个axios拦截器:

// declare a request interceptor
axios.interceptors.request.use(config => {
  // perform a task before the request is sent
  console.log('Request was sent');

  return config;
}, error => {
  // handle the error
  return Promise.reject(error);
});

// sent a GET request
axios.get('https://api.github.com/users/mapbox')
  .then(response => {
    console.log(response.data.created_at);
  });

以上代码会打印每当发送这个请求时,控制台都会打印上面"Request was sent",然后等待,直到服务器返回响应,此时,就会打印这个账号在GitHub上的创建时间(response.data.created_at)。使用拦截器后,你就不用再给每个HTTP请求单独的写一段重复的代码了。

Axios同样提供了响应的拦截器,让我们在服务器向应用返回响应时,统一转换返回值:

// declare a response interceptor
axios.interceptors.response.use((response) => {
  // do something with the response data
  console.log('Response was received');

  return response;
}, error => {
  // handle the response error
  return Promise.reject(error);
});

// sent a GET request
axios.get('https://api.github.com/users/mapbox')
  .then(response => {
    console.log(response.data.created_at);
  });

客户端支持XSRF防御

Cross-site request forgery (简称XSRF,跨站请求伪造)是一种攻击网络托管应用程序的方法,攻击者伪装成合法且受信任的用户,以影响该应用程序与用户浏览器之间的交互。有很多方法可以执行这种攻击,包括XMLHttpRequest

幸好,Axios通过允许用户在发出请求时嵌入额外的认证信息的方式防御XSRF,这使服务器能够发现来自未授权地址的请求。以下是使用方法:

const options = {
  method: 'post',
  url: '/login',
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
};

// send the request
axios(options);

监控POST请求进度

Axios另一个NB的特性是,他可以监控请求的进度。这个功能在我们下载或上传大文件时非常有用。Axios文档上提供了例子,但是简单起见,我们在本教程中使用Axios Progress Bar模块。

首先,我们需要引入相关的脚本和样式

<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/nprogress.css" />

<script src="https://cdn.rawgit.com/rikmms/progress-bar-4-axios/0a3acf92/dist/index.js"></script>

然后我们就可以像下面这样使用进度条啦:

loadProgressBar()

const url = 'https://media.giphy.com/media/C6JQPEUsZUyVq/giphy.gif';

function downloadFile(url) {
  axios.get(url)
  .then(response => {
    console.log(response)
  })
  .catch(error => {
    console.log(error)
  })
}

downloadFile(url);

我们可以这样覆盖默认样式:

#nprogress .bar {
    background: red !important;
}

#nprogress .peg {
    box-shadow: 0 0 10px red, 0 0 5px red !important;
}

#nprogress .spinner-icon {
    border-top-color: red !important;
    border-left-color: red !important;
}

取消请求

有些情况下,你可能不关心请求的结果,并要取消已经发送的请求,这也是可以实现的哦,只需要使用cancelToken。注意,取消请求的功能是在1.5版本添加的,并且基于可取消的promise的提案,下面是使用方法:

const source = axios.CancelToken.source();

axios.get('https://media.giphy.com/media/C6JQPEUsZUyVq/giphy.gif', {
  cancelToken: source.token
}).catch(thrown => {
  if (axios.isCancel(thrown)) {
    console.log(thrown.message);
  } else {
    // handle error
  }
});

// cancel the request (the message parameter is optional)
source.cancel('Request canceled.');

您还可以通过传递执行器函数给CancelToken构造函数来创建CancelToken,如下所示:

onst CancelToken = axios.CancelToken;
let cancel;

axios.get('https://media.giphy.com/media/C6JQPEUsZUyVq/giphy.gif', {
  // specify a cancel token
  cancelToken: new CancelToken(c => {
    // this function will receive a cancel function as a parameter
    cancel = c;
  })
}).catch(thrown => {
  if (axios.isCancel(thrown)) {
    console.log(thrown.message);
  } else {
    // handle error
  }
});

// cancel the request
cancel('Request canceled.');

浏览器兼容

Axios在浏览器兼容上是非常有优势的,即使是IE11也可以很好地兼容。

Chrome Firefox Safari Edge IE
11

结语

在这篇文章中,我们学习了Axios大部分主要的特性,以及他们的使用方法。还有一些文章中没涉及的内容,感兴趣的同学就去官方文档中深入了解吧!