Vue.js官方推薦的Ajax庫Axios入門

簡介

Axios 是一個基于 promise 的 HTTP 庫村缸,可以用在瀏覽器和 node.js 中哭懈。本文先從瀏覽器端學起矗积。

它的特性是:

  • 從瀏覽器中創(chuàng)建 XMLHttpRequests
  • 從 node.js 創(chuàng)建 http 請求
  • 支持 Promise API
  • 攔截請求和響應
  • 轉(zhuǎn)換請求數(shù)據(jù)和響應數(shù)據(jù)
  • 取消請求
  • 自動轉(zhuǎn)換 JSON 數(shù)據(jù)
  • 客戶端支持防御 XSRF

瀏覽器支持

IE9及以上吁恍。

引入

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>

基本用法

先做一個1.php:

<?php

$a['bc'] = 'd';
echo json_encode($a);

然后做一個1.html:

<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>
<script type="text/javascript">
axios.get('1.php')
    .then(function (response) {
        console.log(response);
    })
    .catch(function (error) {
        console.log(error);
    });
</script>

控制臺輸出:

image.png

響應包含以下信息:

{
  // `config` 是為請求提供的配置信息
  config: {}

  // `data` 由服務器提供的響應
  data: {},

  // `headers` 服務器響應的頭
  headers: {},

  // `request` 指向XHR對象
  request: {},

  // `status` 來自服務器響應的 HTTP 狀態(tài)碼
  status: 200,

  // `statusText` 來自服務器響應的 HTTP 狀態(tài)信息
  statusText: 'OK',
}

可以看出,Axios跟jQuery的response有極大區(qū)別骚露,jQuery的response忠實的表達php的響應內(nèi)容,而Axios會給response附加相當多的屬性缚窿。

拋出錯誤

如果是404錯誤棘幸,會拋出:

Error: Request failed with status code 404
    at e.exports (https://cdn.bootcss.com/axios/0.17.1/axios.min.js:8:4479)
    at e.exports (https://cdn.bootcss.com/axios/0.17.1/axios.min.js:8:4321)
    at XMLHttpRequest.l.(anonymous function) (https://cdn.bootcss.com/axios/0.17.1/axios.min.js:8:3278)

加參數(shù)的GET請求

php:

<?php
echo $_GET['ID'];

html:

<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>
<script type="text/javascript">
axios.get('1.php', {
    params: {
      ID: 12345
    }
  })
    .then(function (response) {
        console.log(response);
    })
    .catch(function (error) {
        console.log(error);
    });
</script>

POST請求

官方給出的POST范例如下:

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

但是,這個例子并不能運行成功倦零。官方給出的解決方案是误续,需要使用一個非常新的API:URLSearchParams。這里是它的介紹:https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams 扫茅。使用它之后蹋嵌,就可以正常發(fā)送POST請求了。

var params = new URLSearchParams();
params.append('key', 'value');

axios.post('1.php', params)
.then(function(res){
  console.log(res);
})
.catch(function(err){
  console.log(err);
});

由于IE11以上才支持URLSearchParams(可以參看https://www.caniuse.com/#feat=urlsearchparams)葫隙,所以官方給出了一個墊片方案:https://github.com/WebReflection/url-search-params栽烂,使用方法很簡單,引入<script src="https://cdn.bootcss.com/url-search-params/0.10.0/url-search-params.js"></script>恋脚,然后照常使用即可腺办。

POST上傳文件或Blob

URLSearchParams只能處理url字符串,并不能上傳文件糟描,如果想上傳文件怀喉,可以使用另一個API:FormData。它的使用方法跟URLSearchParams一模一樣:

<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>
<input type="file" id="file">
<button>按鈕</button>
<script type="text/javascript">
document.getElementsByTagName('button')[0].onclick = function () {
    var formdata = new FormData();
    formdata.append('key', 'value');
    formdata.append('file', file.files[0]);

    axios.post('1.php', formdata)
    .then(function(res){
      console.log(res.data);
    })
    .catch(function(err){
      console.log(err);
    });
};
</script>

并發(fā)請求

處理并發(fā)請求的助手函數(shù):

axios.all(iterable) 接收數(shù)組參數(shù)船响,每一個數(shù)組元素都是一個Axios請求
axios.spread(callback) 執(zhí)行并發(fā)并執(zhí)行回調(diào)

function getA() {
  return axios.get('1.php?ID=12345');
}

function getB() {
  return axios.get('1.php?ID=910JQK');
}

function getC() {
  return axios.get('1.php?ID=abcde');
}

axios.all([getA(), getB(), getC()])
  .then(axios.spread(function (a, b, c) {
    // 當所有請求都執(zhí)行完成躬拢,才執(zhí)行此處代碼
    // a 就是第一個請求的響應躲履,其他類推
    console.log(a);
    console.log(b);
    console.log(c);
  }));

方法別名

跟jQuery類似,Axios也搞了很多方法別名估灿,不過通常我們用GET和POST最多:

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

axios API

有兩種形式崇呵。

第一種:axios(config)

// 比如發(fā)送 POST 請求
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});

從上文可知,這種寫法是不會正確執(zhí)行的馅袁,只能修改一下:

    var data = new URLSearchParams();
    data.append('key', '1111');
    axios({
      method: 'post',
      url: '1.php',
      data: data
    })

第二種:axios(url[, config])

axios('/user/12345', {
  method: 'get',
  params: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});

第一種域慷、第二種形式的唯一區(qū)別在于是否把url擇出來。

axios的所有config如下汗销。通常我們不用關(guān)心全部的配置項犹褒,只需要設(shè)置常用的幾個項即可。

{
  //`url`是請求的服務器地址
  url:'/user',
  //`method`是請求資源的方式
  method:'get'//default
  //如果`url`不是絕對地址弛针,那么`baseURL`將會加到`url`的前面
  //當`url`是相對地址的時候叠骑,設(shè)置`baseURL`會非常的方便
  baseURL:'https://some-domain.com/api/',
  //`transformRequest`選項允許我們在請求發(fā)送到服務器之前對請求的數(shù)據(jù)做出一些改動
  //該選項只適用于以下請求方式:`put/post/patch`
  //數(shù)組里面的最后一個函數(shù)必須返回一個字符串、-一個`ArrayBuffer`或者`Stream`
  transformRequest:[function(data){
    //在這里根據(jù)自己的需求改變數(shù)據(jù)
    return data;
  }],
  //`transformResponse`選項允許我們在數(shù)據(jù)傳送到`then/catch`方法之前對數(shù)據(jù)進行改動
  transformResponse:[function(data){
    //在這里根據(jù)自己的需求改變數(shù)據(jù)
    return data;
  }],
  //`headers`選項是需要被發(fā)送的自定義請求頭信息
  headers: {'X-Requested-With':'XMLHttpRequest'},
  //`params`選項是要隨請求一起發(fā)送的請求參數(shù)----一般鏈接在URL后面
  //他的類型必須是一個純對象或者是URLSearchParams對象
  params: {
    ID:12345
  },
  //`paramsSerializer`是一個可選的函數(shù)削茁,起作用是讓參數(shù)(params)序列化
  //例如(https://www.npmjs.com/package/qs,http://api.jquery.com/jquery.param)
  paramsSerializer: function(params){
    return Qs.stringify(params,{arrayFormat:'brackets'})
  },
  //`data`選項是作為一個請求體而需要被發(fā)送的數(shù)據(jù)
  //該選項只適用于方法:`put/post/patch`
  //當沒有設(shè)置`transformRequest`選項時dada必須是以下幾種類型之一
  //string/plain/object/ArrayBuffer/ArrayBufferView/URLSearchParams
  //僅僅瀏覽器:FormData/File/Blob
  //僅node:Stream
  data {
    firstName:"Fred"
  },
  //`timeout`選項定義了請求發(fā)出的延遲毫秒數(shù)
  //如果請求花費的時間超過延遲的時間宙枷,那么請求會被終止

  timeout:1000,
  //`withCredentails`選項表明了是否是跨域請求
  
  withCredentials:false,//default
  //`adapter`適配器選項允許自定義處理請求,這會使得測試變得方便
  //返回一個promise,并提供驗證返回
  adapter: function(config){
    /*..........*/
  },
  //`auth`表明HTTP基礎(chǔ)的認證應該被使用茧跋,并提供證書
  //這會設(shè)置一個authorization頭(header),并覆蓋你在header設(shè)置的Authorization頭信息
  auth: {
    username:"zhangsan",
    password: "s00sdkf"
  },
  //返回數(shù)據(jù)的格式
  //其可選項是arraybuffer,blob,document,json,text,stream
  responseType:'json',//default
  //
  xsrfCookieName: 'XSRF-TOKEN',//default
  xsrfHeaderName:'X-XSRF-TOKEN',//default
  //`onUploadProgress`上傳進度事件
  onUploadProgress:function(progressEvent){
    //下載進度的事件
onDownloadProgress:function(progressEvent){
}
  },
  //相應內(nèi)容的最大值
  maxContentLength:2000,
  //`validateStatus`定義了是否根據(jù)http相應狀態(tài)碼慰丛,來resolve或者reject promise
  //如果`validateStatus`返回true(或者設(shè)置為`null`或者`undefined`),那么promise的狀態(tài)將會是resolved,否則其狀態(tài)就是rejected
  validateStatus:function(status){
    return status >= 200 && status <300;//default
  },
  //`maxRedirects`定義了在nodejs中重定向的最大數(shù)量
  maxRedirects: 5,//default
  //`httpAgent/httpsAgent`定義了當發(fā)送http/https請求要用到的自定義代理
  //keeyAlive在選項中沒有被默認激活
  httpAgent: new http.Agent({keeyAlive:true}),
  httpsAgent: new https.Agent({keeyAlive:true}),
  //proxy定義了主機名字和端口號,
  //`auth`表明http基本認證應該與proxy代理鏈接瘾杭,并提供證書
  //這將會設(shè)置一個`Proxy-Authorization` header,并且會覆蓋掉已經(jīng)存在的`Proxy-Authorization`  header
  proxy: {
    host:'127.0.0.1',
    port: 9000,
    auth: {
      username:'skda',
      password:'radsd'
    }
  },
  //`cancelToken`定義了一個用于取消請求的cancel token
  //詳見cancelation部分
  cancelToken: new cancelToken(function(cancel){

  })
}

創(chuàng)建axios實例

利用axios.create(config)創(chuàng)建實例诅病,我們可以創(chuàng)建一個定制版axios。

下面栗子中粥烁,baseURL:"https://www.baidu.com/"指定了baseURL贤笆,當然了,這個例子的執(zhí)行結(jié)果是拋出錯誤讨阻,大家明白道理即可芥永。

var axiosInstance = axios.create({
  baseURL:"https://www.baidu.com/",
});
axiosInstance('1.php', {
  method: 'get',
  params: {
    ID: '23456'
  }
}).then(function (a) {
  console.log(a);
});

默認配置

在不創(chuàng)建定制版實例的前提下,我們也可以先修改默認配置钝吮。比如:

1恤左、 設(shè)置全局默認配置

axios.defaults.baseURL = 'http://api.exmple.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['content-Type'] = 'appliction/x-www-form-urlencoded';

2、 設(shè)置自定義實例的默認設(shè)置

//當創(chuàng)建實例的時候設(shè)置默認配置
var axiosInstance = axios.create({
    baseURL: 'https://api.example.com'
});

//當實例創(chuàng)建時候修改配置
axiosInstance.defaults.headers.common["Authorization"] = AUTH_TOKEN;

配置的覆蓋規(guī)則

現(xiàn)在我們可以看到搀绣,有三種方式對我們的請求進行配置:

  • 請求之前給axios傳參
  • 定制一個實例
  • 給axios設(shè)置默認配置飞袋,或給實例修改默認配置

那么,配置覆蓋規(guī)則是什么呢链患?

簡單說巧鸭,實例的配置永遠高于axios類的配置,請求之前給axios傳參高于一切麻捻。

攔截器

攔截器英文為interceptor纲仍。攔截器的作用是呀袱,在你的請求發(fā)出之前,或者響應到達之前郑叠,多一次或多次身份驗證夜赵。

因為前后臺交互一定要遵循一個原則:互不信任原則。前端發(fā)送到后臺的參數(shù)必須在前端驗證合法的才能發(fā)送乡革,后臺必須驗證是否合法寇僧,驗證是否符合該參數(shù)的原定數(shù)據(jù)類型和值范圍。后臺返回給前端的數(shù)據(jù)沸版,也必須驗證是否為約定的數(shù)據(jù)結(jié)構(gòu)和值類型嘁傀。

例如:你寫了幾個請求數(shù)據(jù)的接口,開啟服務后视粮,用戶沒登錄直接訪問這些接口细办,也是可以拿到數(shù)據(jù)的,但這就違背了后臺管理系統(tǒng)必須先登錄的原則蕾殴,有心人就會利用這個bug來竊取你的數(shù)據(jù)庫數(shù)據(jù)笑撞。所以讓攔截器攔截這種非法請求。

攔截分為請求發(fā)送前的攔截钓觉,和接到響應數(shù)據(jù)前的攔截茴肥。看個栗子:

//添加一個請求攔截器
axios.interceptors.request.use(function(config){
  console.log('尚未發(fā)出請求');
  return config;
},function(err){
  return Promise.reject(error);
});

//添加一個響應攔截器
axios.interceptors.response.use(function(res){
  console.log('尚未處理響應');
  return res;
},function(err){
  return Promise.reject(error);
});

axios('1.php', {
  method: 'get'
}).then(function (a) {
  console.log(a);
});

輸出:

尚未發(fā)出請求
尚未處理響應
Object {data: 111, status: 200, statusText: "OK", headers: Object, config: Object…}

你可能會說议谷,我在發(fā)送請求之前先做條件判斷不行么?條件判斷通過才發(fā)送請求堕虹,不可以么卧晓?可以雖然是可以,但是這不符合面向?qū)ο蟮脑瓌t赴捞,因為先寫驗證然后寫發(fā)送逼裆,這是面向過程的,還有一個弊端是會造成重復代碼赦政,不方便管理胜宇,因為你每寫一處請求,就要先寫一片驗證代碼恢着。

觀察代碼桐愉,你會發(fā)現(xiàn)攔截器的回調(diào)函數(shù)里面有一個config,這是干嘛的掰派?我們打印一下它:

image.png

簡單說从诲,config是一組可修改的配置項,比如靡羡,我們修改url系洛,改成2.php俊性,看看會有什么現(xiàn)象:

//添加一個請求攔截器
axios.interceptors.request.use(function(config){
  config.url = '2.php';
  return config;
},function(err){
  return Promise.reject(error);
});

axios('1.php', {
  method: 'get'
}).then(function (a) {
  console.log(a);
});

結(jié)果呢,由于我根本沒有2.php描扯,所以直接報錯了定页。

然后,響應攔截器里面的res又是什么呢绽诚?這個就簡單了典徊,它指向Axios的響應對象。

攔截器的注意事項:

  • 攔截器必須在請求前設(shè)置才有效憔购,所以注意代碼先后順序宫峦。
  • 直接為axios全局對象創(chuàng)建攔截器,會導致全局的axios發(fā)出的請求或接收的響應都會被攔截到玫鸟,實踐中不要做事做這么絕导绷,所以應該使用axios.create()來創(chuàng)建單獨的axios實例,然后給實例設(shè)置攔截器屎飘。

錯誤處理

符合標準Promises的錯誤處理方法妥曲,就是用catch()來捕獲。

axios.get('/user/12345')
  .catch(function(error){
    if(error.response){
      //請求已經(jīng)發(fā)出钦购,但是服務器響應返回的狀態(tài)嗎不在2xx的范圍內(nèi)
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.header);
    }else {
      //一些錯誤是在設(shè)置請求的時候觸發(fā)
      console.log('Error',error.message);
    }
    console.log(error.config);
  });

取消請求

先寫例子:

1.php如下檐盟,php的作用是,5秒鐘之后返回111押桃。

<?php
sleep(5);
echo 111;

html:

<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>
<button>1111</button>
<script type="text/javascript">
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('1.php', {
  cancelToken: source.token
}).then(function (response) {
  console.log(response);
}, function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled - ', thrown.message);
  } else {
    // handle error
  }
});

document.getElementsByTagName('button')[0].onclick = function () {
    source.cancel();
}
</script>

在不點擊按鈕的前提下葵萎,5秒鐘之后,順利的打印了response對象唱凯。如果5秒鐘之內(nèi)點擊了按鈕羡忘,則屬于異常,會被捕獲磕昼。打印Request canceled - undefined卷雕。

我們分析一下:

var CancelToken = axios.CancelToken; 是創(chuàng)建一個取消令牌對象
var source = CancelToken.source(); 是取得這個對象的資源對象

說實話這2句的原理,很少有文獻能查到票从,所以我們暫時不去了解原理漫雕,只需要知道,我們操作source就可以取消請求峰鄙。

取消請求的代碼就一句source.cancel();浸间,可以加字符串參數(shù),用于說明取消的原因吟榴。

然后发框,我們在Axios的配置項里加入cancelToken: source.token,這個的意義在于,程序怎么知道你要取消哪個請求呢梅惯?就靠這個令牌來識別到底是該取消哪個請求宪拥。

另一種寫法是:

<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>
<button>1111</button>
<script type="text/javascript">
var CancelToken = axios.CancelToken;
var cancel;
axios.get('1.php', {
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
}).then(function (response) {
  console.log(response);
}, function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

document.getElementsByTagName('button')[0].onclick = function () {
    cancel();
}
</script>

這個理解起來更麻煩,推薦用第一種铣减。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末她君,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子葫哗,更是在濱河造成了極大的恐慌缔刹,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劣针,死亡現(xiàn)場離奇詭異校镐,居然都是意外死亡,警方通過查閱死者的電腦和手機捺典,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門鸟廓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人襟己,你說我怎么就攤上這事引谜。” “怎么了擎浴?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵员咽,是天一觀的道長。 經(jīng)常有香客問我贮预,道長贝室,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任仿吞,我火速辦了婚禮滑频,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茫藏。我一直安慰自己误趴,他們只是感情好霹琼,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布务傲。 她就那樣靜靜地躺著,像睡著了一般枣申。 火紅的嫁衣襯著肌膚如雪售葡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天忠藤,我揣著相機與錄音挟伙,去河邊找鬼。 笑死模孩,一個胖子當著我的面吹牛尖阔,可吹牛的內(nèi)容都是我干的贮缅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼介却,長吁一口氣:“原來是場噩夢啊……” “哼谴供!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起齿坷,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤桂肌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后永淌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崎场,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片孕暇。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡购撼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亭姥,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布污呼,位于F島的核電站,受9級特大地震影響包竹,放射性物質(zhì)發(fā)生泄漏燕酷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一周瞎、第九天 我趴在偏房一處隱蔽的房頂上張望苗缩。 院中可真熱鬧,春花似錦声诸、人聲如沸酱讶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泻肯。三九已至,卻和暖如春慰照,著一層夾襖步出監(jiān)牢的瞬間灶挟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工毒租, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稚铣,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像惕医,于是被迫代替她去往敵國和親耕漱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359