如何使用Axios像专业人士一样发出HTTP请求

1,721 阅读7分钟

前端程序与服务器通信的最常见方式是通过HTTP协议。其中使用Fetch API和XMLHttpRequest
接口,可以获取资源并发出HTTP请求。

如果编程中使用的是JavaScript库,则该库可能附带客户端HTTP API。例如$.ajax()jQuery的功能在前端开发人员中特别受欢迎。但是,随着开发人员从此类库转而使用原生API,专用HTTP客户端应运而生。

在本文中,我将对自己学习的Axios(基于XMLHttpRequest浏览器提供接口的客户端HTTP API)主要关键功能进行很好的介绍

为什么选择Axios?

与Fetch一样,Axios也基于Promise的HTTP库。但是,它提供了更强大,更灵活的功能集。与Fetch API相比,优势包括:

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

安装

您可以使用以下方法安装Axios:
  • npm:
     npm install axios
  • Bower程序包管理器:
    bower install axios
  • 使用 cdn::
    <script src="https://unpkg.com/axios/dist/axios.min.js"></scropt>

发出请求

发出HTTP请求就像将配置对象传递给Axios函数一样。以最简单的形式,对象必须具有一个url属性。如果未提供任何方法,GET将用作默认值。让我们看一个简单的例子:

// 发送一个 POST 请求
axios({
  method: 'post',
  url: '/login',
  data: {
    firstName: 'Finn',
    lastName: 'Williams'
  }
});

对于使用jQuery的 $.ajax 人来说,这应该看起来很熟悉这段代码只是指示Axios向其/login发送POST请求,并将键/值对的对象作为其数据。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。要处理结果,可以使用如下 then() 方法:

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

如果实现了Promise,则将调用then()第一个参数;如果Promise被拒绝,将调用第二个参数。根据文档,响应的对象是一个包含以下信息的对象:

{
  //`data`是服务器提供的响应
  data: {},  
  //`status`是服务器响应中的HTTP状态代码
  status: 200,  
  //`statusText`是服务器响应中的HTTP状态消息
  statusText :'ok', 
 
  //`headers`服务器响应的标题
  //所有标题名称均小写
  headers: {},  
  //`config`是为请求提供给`axios`的配置
  config :{}, 
 
  //`request`是生成此响应的请求
  //这是node.js中的最后一个ClientRequest实例(在重定向中)
  //和一个XMLHttpRequest实例的浏览器
  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: {

同时发出请求

Axios更有趣的功能之一是它能够通过将一组参数传递给方法来并行发出多个请求此方法axios.all()返回一个promise对象,仅在数组中所有参数请求完时才解析。这是一个简单的例子:

//执行同时请求 
axios.all([
  axios.get('https://api.github.com/users/mapbox'),
  axios.get('https://api.github.com/users/phantomjs')
])
.then(responseArr => {
  //当所有请求执行完后才执行
  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发出两个请求,然后将created_at每个响应属性值记录到控制台。如果任何一个参数被拒绝,那么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);
}));

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

该代码的输出与前面的示例相同。唯一的区别是该axios.spread()方法用于从响应数组返回值给指定的变量。

发送自定义标题

使用Axios发送自定义标头非常简单。只需传递一个包含标题的对象作为最后一个参数。例如:

const options = {
  headers: {'X-Custom-Header': 'value'}
};
axios.post('/save', { a: 10 }, options);   

转换请求和响应

默认情况下,Axios自动将请求和响应转换为JSON。但是,它也允许您覆盖默认行为并定义不同的转换机制。当使用仅接受特定数据格式(例如XML或CSV)的API时,此功能特别有用。要在将请求数据发送到服务器之前更改请求数据transformRequest,请在config对象中设置属性。注意,此方法仅适用于PUTPOSTPATCH请求方法。执行的操作:

const options = { 
   method: 'post',
   url: '/login',
   data: {
   firstName: 'Finn',
   lastName: 'Williams'
  },
  transformRequest:[ (data,headers)=> {   
    //转换数据
    return data;
  }]
};

//发送请求
axios(options);
要在将数据传递给then()catch()之前对其进行修改,可以设置transformResponse属性:

const options = {
  method: 'post',
  url: '/login',
  data: {
    firstName: 'Finn',
    lastName: 'Williams'
  },
  transformResponse: [(data) => {
    // 转换数据
    return data;
  }]
};

// 发送数据
axios(options);

拦截请求和响应

HTTP拦截是Axios的常用功能。使用此功能,您可以检查程序中的HTTP请求并将其从服务器更改为服务器,反之亦然,这对于各种隐式任务(例如日志记录和身份验证)非常有用。

乍一看,拦截器看起来非常像转换,但是它们在一个关键方面有所不同:与仅接收数据和标头作为参数的转换不同,拦截器接收整个响应对象或请求配置。

您可以在Axios中声明请求拦截器,如下所示:

// 声明一个请求拦截器
axios.interceptors.request.use(config => {
  // perform a task before the request is sent
  console.log('Request was sent');

  return config;
}, error => {
  // 处理错误
  return Promise.reject(error);
});

// 发送get请求
axios.get('https://api.github.com/users/mapbox')
  .then(response => {
    console.log(response.data.created_at);
  });

每当发送请求时,此代码都会向控制台记录一条消息,然后等待直到服务器收到响应为止,这时它将在GitHub上向控制台打印创建帐户的时间。使用拦截器的一个优点是您不再需要为每个HTTP请求分别实现任务。

Axios还提供了响应拦截器,使您可以将服务器中的响应转换回应用程序:

// 声明一个请求拦截器
axios.interceptors.response.use((response) => {
  // do something with the response data
  console.log('Response was received');

  return response;
}, error => {
  // 处理错误请求
  return Promise.reject(error);
});

// 发送get请求
axios.get('https://api.github.com/users/mapbox')
  .then(response => {
    console.log(response.data.created_at);
  });

客户端支持以防XSRF

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

幸运的是,Axios旨在通过允许您在发出请求时嵌入其他身份验证数据来防止XSRF。这使服务器能够发现来自未授权位置的请求。这是使用Axios可以完成的方法:

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

// 发送请求
axios(options);

监控POST请求进度

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;
}

取消请求

在某些情况下,您可能不再关心结果,而是想要取消已发送的请求。这可以通过使用取消令牌来完成。取消请求的功能已在1.5版中添加到Axios,它基于可取消的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 {
    // 处理错误
  }
});

// c取消请求 (信息是一个可选项l)
source.cancel('Request canceled.');

您还可以通过将执行程序函数传递给CancelToken构造函数来创建取消令牌,如下所示:

const 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 {
    // 处理错误
  }
});

// 取消请求
cancel('Request canceled.')

浏览器支持

关于浏览器支持,Axios非常可靠。甚至IE 11之类的旧版浏览器也可以与Axios很好地配合使用。它还支持Chrome、Firefox、Safari、Edge。