axios入門實踐

一 前言

本文適合剛接觸axios或者使用過幾回的同窗來分享交流一些入門經驗,本文一樣適用熟悉axios的同窗來做爲參考手冊。
默認你已經看過axios的相關文檔:axios文檔 GitHub,經過文檔瞭解基礎的使用以後,接下來你能夠進入正文。ios

二 正文

axios = Ajax + 異步處理git

1.axios的get與post方法傳入參數的區別

(1)getgithub

axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

(2)postaxios

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

get是放在參數對象的params屬性裏面,post是直接放在參數對象裏面。後端

2.學會使用axios.create( )建立axios實例

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

建立實例的好處:統一(批量)處理request/response
(1)例如你在每次的請求中都要帶 cookie, 你或許能夠在每一個請求中這麼寫:api

axios.get('/user1',{withCredentials:true});
axios.get('/user2',{withCredentials:true});
... ...

可是你也能夠這麼用:promise

var instance = axios.create({
    withCredentials:true
    });
   instance.get('/user1').then();
   instance.get('/user2').then();
    ... ...

(2)若是你的多個請求前綴都是相同的,那麼你就可使用baseUrl
bad:服務器

axios.get('http://www.baidu.com/api/city').then();
axios.get('http://www.baidu.com/api/region').then();
axios.get('http://www.baidu.com/api/user').then();

good:cookie

var instance = axios.create({
    baseUrl: http://www.baidu.com/api
    });
instance.get('/city').then();
instance.get('/region').then();
instance.get('/user').then();

(3)其餘方法推薦
設置超時時間:timeout
設置報文頭:header
等等網絡

3.功能強大的攔截器:在請求或響應被 then 或 catch 處理前攔截它們

(1)使用與取消
咱們能夠這麼用:

// 添加請求攔截器
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);
  });

建議將攔截器掛在到實例上:

var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

若是你想在稍後移除攔截器,能夠這樣:

var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

(2)注意事項
攔截器能夠攔截請求和攔截響應,在請求或響應被 then 或 catch 處理前攔截它們。
它接受兩個函數類型的參數,一個是成功請求/返回的函數,一個是失敗請求/返回的函數;能夠在這些函數裏面作一些事情,例如對於401未受權的錯誤,咱們能夠重定向到登錄頁:

instance.interceptors.response.use(function (res) {
    return res;
},function(error){
    if (error.response.status === 401) {
        login();
        return;
      }
});

須要記住的是一旦你返回成功,若是沒什麼事可作,其餘的事交給then以後來作,記得返回response/request,否則then接受不到響應。

(3)使用了攔截器處理相關問題,這樣就再也不須要使用catch來作錯誤的處理。

4.萬惡的攔截器

instance.interceptors.response.use(function (res) {
    return res;
},function(error){
    if (error.response.status === 401) {
        /*一些處理*/
        throw error;
      }
});

不管是對成功的處理仍是對失敗的處理,若是攔截器不拋出錯誤throw error,那麼終將還會執行then裏面處理請求成功的函數,即便你返回undefined。
因此,建議在錯誤處理的最後拋出錯誤!

5.可供參考的二次封裝

轉載文章連接:https://juejin.im/post/5a293e...

//引入axios
import axios from 'axios'

let cancel ,promiseArr = {}
const CancelToken = axios.CancelToken;
//請求攔截器
axios.interceptors.request.use(config => {
    //發起請求時,取消掉當前正在進行的相同請求
    if (promiseArr[config.url]) {
        promiseArr[config.url]('操做取消')
        promiseArr[config.url] = cancel
    } else {
        promiseArr[config.url] = cancel
    }
      return config
}, error => {
    return Promise.reject(error)
})

//響應攔截器即異常處理
axios.interceptors.response.use(response => {
    return response
}, error => {
    if (error && error.response) {
      switch (error.response.status) {
        case 400:
          error.message = '錯誤請求'
          break;
        case 401:
          error.message = '未受權,請從新登陸'
          break;
        case 403:
          error.message = '拒絕訪問'
          break;
        case 404:
          error.message = '請求錯誤,未找到該資源'
          break;
        case 405:
          error.message = '請求方法未容許'
          break;
        case 408:
          error.message = '請求超時'
          break;
        case 500:
          error.message = '服務器端出錯'
          break;
        case 501:
          error.message = '網絡未實現'
          break;
        case 502:
          error.message = '網絡錯誤'
          break;
        case 503:
          error.message = '服務不可用'
          break;
        case 504:
          error.message = '網絡超時'
          break;
        case 505:
          error.message = 'http版本不支持該請求'
          break;
        default:
          error.message = `鏈接錯誤${error.response.status}`
      }
    } else {
      error.message = "鏈接到服務器失敗"
    }
    Message.error(error);//Message 一個UI提示組件
      return Promise.resolve(error.response)
})

axios.defaults.baseURL = '/api'
//設置默認請求頭
axios.defaults.headers = {
    'X-Requested-With': 'XMLHttpRequest'
}
axios.defaults.timeout = 10000

export default {
  //get請求
    get (url,param) {
      return new Promise((resolve,reject) => {
        axios({
          method: 'get',
          url,
          params: param,
          cancelToken: new CancelToken(c => {
            cancel = c
          })
        }).then(res => {
          resolve(res)
        })
      })
    },
  //post請求
    post (url,param) {
      return new Promise((resolve,reject) => {
        axios({
          method: 'post',
          url,
          data: param,
          cancelToken: new CancelToken(c => {
            cancel = c
          })
        }).then(res => {
          resolve(res)
        })
      })
     }
  }

注意:這段代碼中沒有建立axios實例,我的以爲建立實例會更方便調用。
根據官方文檔,如何取消一個還沒有獲得響應的請求:

var CancelToken = axios.CancelToken;
var cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();

6.axios 失敗從新請求的封裝

//在main.js設置全局的請求次數,請求的間隙
axios.defaults.retry = 4;
axios.defaults.retryDelay = 1000;

axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    var config = err.config;
    // If config does not exist or the retry option is not set, reject
    if (!config || !config.retry) return Promise.reject(err);

    // Set the variable for keeping track of the retry count
    config.__retryCount = config.__retryCount || 0;

    // Check if we've maxed out the total number of retries
    if (config.__retryCount >= config.retry) {
        // Reject with the error
        return Promise.reject(err);
    }

    // Increase the retry count
    config.__retryCount += 1;

    // Create new promise to handle exponential backoff
    var backoff = new Promise(function (resolve) {
        setTimeout(function () {
            resolve();
        }, config.retryDelay || 1);
    });

    // Return the promise in which recalls axios to retry the request
    return backoff.then(function () {
        return axios(config);
    });
});

7.更實用的封裝

  1. 一般不須要請求失敗以後再從新請求
  2. 請求失敗以後不須要把錯誤提示的那麼詳細
  3. 一般在請求時還伴隨加載狀態【重要】

示例代碼:

// 建立axios實例
const axiosInstance = axios.create({
  // timeout: 3000,
  // baseURL,
  withCredentials: true,
});

 // request攔截器
 axiosInstance.interceptors.request.use((config) => config,             
   (error) => Promise.reject(error));
           axiosInstance.interceptors.response.use((response:AxiosResponse)=> {
  const {data} = response || {data:{}};
  return Promise.resolve(data);
}, (error:any) => {
  if(error&&error.response){ 
    // 提示具體接口報錯
    return Promise.resolve(error.response);
  }else{
    const response = {
      code:1, // 表示錯誤的code碼
      message:'網絡鏈接錯誤',
    }
    // 提示「網絡鏈接錯誤」
    return Promise.resolve(response);
  }
});

export default axiosInstance;

和上面的參考封裝有如下不一樣之處:

  • 攔截器裏只拋出網絡鏈接失敗的錯誤
  • 不管服務器返回的請求是成功(200)仍是失敗(404 500等),都會被resolve,這就會有三點影響:

    • 業務邏輯上.then(()=>{})的時候都會走resolve的函數,這樣就能夠在這個函數裏控制loading狀態
    • resolve的函數須要根據後端response的成功標示來判斷請求是成功仍是失敗
    • 這樣就再也不須要.catch()

三 後記

簡單的介紹了一些常見事項和基礎用法,有更多的內容等待你們去探索,歡迎留言交流~~

相關文章
相關標籤/搜索