首頁  >  文章  >  web前端  >  解析vue中axios的封裝請求(附步驟碼)

解析vue中axios的封裝請求(附步驟碼)

藏色散人
藏色散人轉載
2022-08-10 10:05:541700瀏覽

一、簡介

axios 是一個輕量的HTTP客戶端,它基於XMLHttpRequest 服務來執行HTTP 請求,支援豐富的配置,支援Promise,支援瀏覽器端和Node.js 端。自Vue2.0起,尤大大宣布取消對vue-resource 的官方推薦,轉而推薦 axios。現在 axios 已成為大部分 Vue 開發者的首選。 ( 如果你還不熟悉axios,可以在這裡查看它的API。)【相關推薦:vue.js影片教學

#封裝前,先來看下,不封裝的情況下,一個實際項目中axios請求的樣子。

大概是長這樣:

axios('http://localhost:3000/data', {
  method: 'GET',
  timeout: 1000,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'xxx',
  },
  transformRequest: [function (data, headers) {
    return data;
  }],
  // 其他请求配置...
})
.then((data) => {
  // todo: 真正业务逻辑代码
  console.log(data);
}, (err) => {
  if (err.response.status === 401) {
  // handle authorization error
  }
  if (err.response.status === 403) {
  // handle server forbidden error
  }
  // 其他错误处理.....
  console.log(err);
});

可以看到在這段程式碼中,頁面程式碼邏輯只在第15行處,上方的一大塊請求配置程式碼和下方一大塊回應錯誤處理程式碼,幾乎跟頁面功能沒有關係,而且每個請求中這些內容都差不多,甚至有的部分完全一樣。

二、封裝後

1.封裝步驟

#封裝的本質就是在待封裝的內容外面加入各種東西,然後把它們作為一個新的整體呈現給使用者,以達到擴展和易用的目的。

封裝axios 要做的事情,就是把所有HTTP請求共用的配置,事先都在axios上配置好,預留好必要的參數和接口,然後把它作為新的axios返回。

目錄結構如下(由Vue-cli 3.0 產生):

|--public/
|--mock/
| |--db.json  # 我新建的介面模擬資料
|--src/
|   |--assets/
|   |--components/
|   |--router/
|   |--store/
|   |--views/
|       |--Home.Vue
|   |--App.vue
|   |--main.js
| |--theme.styl
|--package.json
|...

#2.封裝目標

##在Home 頁,發起axios 請求時就像呼叫一個只有少量參數的方法一樣簡單,這樣我就可以專注於業務程式碼了。

1. 將axios 封裝到一個獨立的檔案

    #在src下建立utils/http.js 檔案
  •   cd src
      mkdir utils
      touch http.js
    引入axios
  •   // src/utils/http.js
      import axios from 'axios';
    建立一個類別
  •   //src/utils/http.js
      //...
      class NewAxios {
      
      }
    給不同環境配置不同請求位址
根據

process.env.NODE_ENV 配置不同的baseURL,讓專案只需執行對應打包指令,就可以在不同環境中自動切換請求主機位址。

// src/utils/http.js

//...
const getBaseUrl = (env) => {
  let base = {
    production: '/',
    development: 'http://localhost:3000',
    test: 'http://localhost:3001',
  }[env];
  if (!base) {
    base = '/';
  }
  return base;
};

class NewAxios {
  constructor() {
    this.baseURL = getBaseUrl(process.env.NODE_ENV);
  }
}

    配置逾時時間

timeout屬性,我一般設定10秒。

// src/utils/http.js

//...
class NewAxios {
  constructor() {
    //...
    this.timeout = 10000;
  }
}

    配置允許攜帶憑證

widthCredentials屬性設為true

// src/utils/http.js

//...
class NewAxios {
  constructor() {
    //...
    this.withCredentials = true;
  }
}

    #給這個類別建立實例上的方法request

request 方法裡,建立新的axios實例,接收請求配置參數,處理參數,新增配置,回傳axios實例的請求結果(一個promise物件)。

你也可以不創建,直接使用預設匯出的axios實例,然後把所有設定都放到它上面,不過這樣一來整個專案就會共用一個axios實例。雖然大部分項目下這樣夠用沒問題,但是有的項目中不同服務地址的請求和回應結構可能完全不同,這個時候共用一個實例就沒辦法支援了。所以為了封裝可以更通用,更具彈性,我會使用

axioscreate方法,讓每次發送請求都是新的axios實例。

// src/utils/http.js

//...
class NewAxios {
  //...
  request(options) {
    // 每次请求都会创建新的axios实例。
    const instance = axios.create();
    const config = { // 将用户传过来的参数与公共配置合并。
      ...options,
      baseURL: this.baseURL,
      timeout: this.timeout,
      withCredentials: this.withCredentials,
    };
    // 配置拦截器,支持根据不同url配置不同的拦截器。
    this.setInterceptors(instance, options.url);
    return instance(config); // 返回axios实例的执行结果
  }
}

因為攔截器配置內容比較多,所以封裝成一個內部函數了。

    設定請求攔截器
在發送請求前對請求參數所做的所有修改都在這裡統一配置。例如統一添加token憑證、統一設定語言、統一設定內容類型、指定資料格式等等。做完後記得返回這個配置,否則整個請求不會進行。

我這裡就設定一個

token

// src/utils/http.js

//...
class NewAxios {
  //...
  // 这里的url可供你针对需要特殊处理的接口路径设置不同拦截器。
  setInterceptors = (instance, url) => { 
    instance.interceptors.request.use((config) => { // 请求拦截器
      // 配置token
      config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || '';
      return config;
    }, err => Promise.reject(err));
  }
  //...
}

    配置回應攔截器
在請求的

thencatch處理前對回應資料進行一輪預先處理。例如過濾回應數據,更多的,是在這裡對各種回應錯誤碼進行統一錯誤處理,還有斷網處理等等。

我這裡就判斷403和斷網。

// src/utils/http.js

//...
class NewAxios {
  //...
  setInterceptors = (instance, url) => {
    //...
    instance.interceptors.response.use((response) => { // 响应拦截器
      // todo: 想根据业务需要,对响应结果预先处理的,都放在这里
      console.log();
      return response;
    }, (err) => {
      if (err.response) { // 响应错误码处理
        switch (err.response.status) {
          case '403':
            // todo: handler server forbidden error
            break;
            // todo: handler other status code
          default:
            break;
        }
        return Promise.reject(err.response);
      }
      if (!window.navigator.online) { // 断网处理
        // todo: jump to offline page
        return -1;
      }
      return Promise.reject(err);
    });
  }
  //...
}

另外,在攔截器裡,也適合放置loading等緩衝效果:在請求攔截器裡顯示loading,在回應攔截器裡移除loading。這樣所有請求就都有了一個統一的loading效果。

    預設匯出新的實例
  •   // src/utils/http.js
      
      //...
      export default new NewAxios();

最後完整的程式碼如下:

// src/utils/http.js

import axios from 'axios';

const getBaseUrl = (env) => {
  let base = {
    production: '/',
    development: 'http://localhost:3000',
    test: 'http://localhost:3001',
  }[env];
  if (!base) {
    base = '/';
  }
  return base;
};

class NewAxios {
  constructor() {
    this.baseURL = getBaseUrl(process.env.NODE_ENV);
    this.timeout = 10000;
    this.withCredentials = true;
  }

  // 这里的url可供你针对需要特殊处理的接口路径设置不同拦截器。
  setInterceptors = (instance, url) => {
    instance.interceptors.request.use((config) => {
      // 在这里添加loading
      // 配置token
      config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || '';
      return config;
    }, err => Promise.reject(err));

    instance.interceptors.response.use((response) => {
      // 在这里移除loading
      // todo: 想根据业务需要,对响应结果预先处理的,都放在这里
      return response;
    }, (err) => {
      if (err.response) { // 响应错误码处理
        switch (err.response.status) {
          case '403':
            // todo: handler server forbidden error
            break;
            // todo: handler other status code
          default:
            break;
        }
        return Promise.reject(err.response);
      }
      if (!window.navigator.online) { // 断网处理
        // todo: jump to offline page
        return -1;
      }
      return Promise.reject(err);
    });
  }

  request(options) {
    // 每次请求都会创建新的axios实例。
    const instance = axios.create();
    const config = { // 将用户传过来的参数与公共配置合并。
      ...options,
      baseURL: this.baseURL,
      timeout: this.timeout,
      withCredentials: this.withCredentials,
    };
    // 配置拦截器,支持根据不同url配置不同的拦截器。
    this.setInterceptors(instance, options.url);
    return instance(config); // 返回axios实例的执行结果
  }
}

export default new NewAxios();

現在

axios 封裝算是完成了80%。我們還需要再進一步把axios和介面結合再封裝一層,才能達到我在一開始定的封裝目標。

3. 使用新的 axios 封裝API

  • 在 src 目录下新建 api 文件夹。把所有涉及HTTP请求的接口统一集中到这个目录来管理。
  • 新建 home.js。我们需要把接口根据一定规则分好类,一类接口对应一个js文件。这个分类可以是按页面来划分,或者按模块等等。为了演示更直观,我这里就按页面来划分了。实际根据自己的需求来定。
  • 使用新的 axios 封装API(固定url的值,合并用户传过来的参数),然后命名导出这些函数。
// src/api/home.js 

import axios from '@/utils/http';
export const fetchData = options => axios.request({
  ...options,
  url: '/data',
});
export default {};

在 api 目录下新建 index.js,把其他文件的接口都在这个文件里汇总导出。

 // src/api/index.js
  
  export * from './home';

这层封装将我们的新的axios封装到了更简洁更语义化的接口方法中。

现在我们的目录结构长这样:

|--public/
|--mock/
|   |--db.json  # 接口模拟数据
|--src/
|   |--api/     # 所有的接口都集中在这个目录下
|       |--home.js  # Home页面里涉及到的接口封装在这里
|       |--index.js # 项目中所有接口调用的入口
|   |--assets/
|   |--components/
|   |--router/
|   |--store/
|   |--utils/
|       |--http.js  # axios封装在这里
|   |--views/
|       |--Home.Vue
|   |--App.vue
|   |--main.js
|   |--theme.styl
|--package.json
|...

4.使用封装后的axios

现在我们要发HTTP请求时,只需引入 api 下的 index.js 文件就可以调用任何接口了,并且用的是封装后的 axios。

// src/views/Home.vue

<template>
  <div class="home">
    <h1>This is home page</h1>
  </div>
</template>

<script>
// @ is an alias to /src
import { fetchData } from &#39;@/api/index&#39;;

export default {
  name: &#39;home&#39;,
  mounted() {
    fetchData()  // axios请求在这里
      .then((data) => {
        console.log(data);
      })
      .catch((err) => {
        console.log(err);
      });
  },
};
</script>

axios请求被封装在fetchData函数里,页面请求压根不需要出现任何axios API,悄无声息地发起请求获取响应,就像在调用一个简单的 Promise 函数一样轻松。并且在页面中只需专注处理业务功能,不用被其他事物干扰。

以上是解析vue中axios的封裝請求(附步驟碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:jb51.net。如有侵權,請聯絡admin@php.cn刪除