Vue自用ES6 Async 風格的api請求文件封裝(fetch,axios,post,get)

api調(diào)用實例

...
methed: {
  ...
  // 根據(jù)賬戶查詢用戶的api
  async getUser() {
    const {account} = this
    const data = {
      account 
    }
    await this.$api
              .getUsers({
                data,
                // 成功回調(diào)
                onSuccess: res => {
                  // ?. 為選擇鏈式調(diào)用, 如果data為null, 不會報錯,會返回undefined, 需要polify
                  let list = res ?.data ?.pageData || []
                  // 處理數(shù)據(jù)
                  list.forEach((item, index) => {
                    item.children && delete item.children;
                    item.key = index
                  });
                  this.list = list;
                }
              })
  },
  mounted() {
    this.loading = true
    await this.getUser()

    await this.anotherApi
    await this.anotherApi
    await this.anotherApi

    this.loading = false
  }
  ...
}

請求前, 可以打開loading開關(guān), await 調(diào)用接口請求函數(shù), 可以在請求完成后, 再繼續(xù)運行程序, 關(guān)閉loading開關(guān)

fetch.js封裝過程

  • axios

  import axios from 'axios'

axios中文文檔

axios 是一個基于 promise 用于瀏覽器和 nodejs 的 http 客戶端,本身具有以下特征:

  • 從瀏覽器中創(chuàng)建 XMLHttpRequest
  • 從 nodejs 發(fā)出 http 請求
  • 支持 Promise API
  • 攔截請求和響應(yīng)
  • 轉(zhuǎn)換請求和響應(yīng)數(shù)據(jù)
  • 取消請求
  • 自動轉(zhuǎn)換 JSON 數(shù)據(jù)
  • 客戶端支持防止 CSRF / XSRF

axios 對vue有非常高的支持度, 很多vue項目都是用axios作為api請求插件. 網(wǎng)上也有非常多對axios進行二次封裝的文章, 筆者也是參考了總多封裝方法, 最后自己修改設(shè)計了這套自用模板. axios的具體是用方法此處就不詳細介紹, 如果對axios還不是非常熟悉, 可以直接訪問文檔進行學習.

除了axios, 也還有fetch等其他api請求方案, 也可以根據(jù)不同的請求方案, 對fetch.js文件進行修改, 以滿足需求.

  • message

import {
  notification
} from 'ant-design-vue'
...
function message(msg) {
  notification.error({
    message: "服務(wù)器請求異常",
    description: "提示:" + msg
  })
}

message 模塊是用于接口提示信息拋出的模塊. 比如, 一個修改數(shù)據(jù)的接口, 在接口請求成功后, 返回成功code. 此時就可以用message彈出一個提示信息, 提示用戶修改成功. 請求失敗也是同理, 可以拋出失敗原因等.可以根據(jù)項目, 修改對應(yīng)的組件. 例如element的 messageBox等.

  • defaultSetting

// 默認請求配置
const defaultSetting = {
  // 請求方法
  method: 'GET',
  // 超時時間ms
  timeout: 600000,
  // res.code成功判定范圍
  statusMin: 0,
  statusMax: 99999,
  // 全局失敗回調(diào)
  onGlobalFail: function (res) {
    message(res.message || res.msg)
  },
  // 成功條件計算方法
  computeSuccess: function (res) {
    if (res.status > 299) return false
    return 1 === res.data.code
  }
}

defaultSetting默認設(shè)置, 這里可以配置一些默認參數(shù)

  • method 請求方法(GET, PSOT, ...)

  • timeout 請求超時判斷時間ms

  • statusMin, statusMax 請求返回狀態(tài)碼判定成功的范圍,例如min設(shè)置為200, max設(shè)置為399. 則403, 404等狀態(tài)碼的請求會被判定為請求失敗, 執(zhí)行請求失敗分支.(這個狀態(tài)碼配置的是aixos插件的成功判斷, 由于筆者自己寫了成功與失敗的分支, 所以這里設(shè)置了0-99999都為成功, 即所有情況下都把結(jié)果返回, 由自定義的方法去判斷請求是否成功)

  • onGlobalFail [Function] 全局失敗回調(diào). 這個方法可以接受一個res的參數(shù),即請求結(jié)果. 當自定義方法判定請求失敗時執(zhí)行.此方法默認為全局方法, 會應(yīng)用于所有請求. 這個方法默認為使用之前定義的message方法, 彈出一個提示框, 展示失敗信息. 可以在調(diào)用具體接口時覆蓋此方法.

  • computeSuccess 此方法用于計算成功狀態(tài),接受res參數(shù), 即請求結(jié)果. 此方法返回一個boolean值, true時執(zhí)行請求成功邏輯, false時執(zhí)行請求失敗邏輯.

  • config


export default async ({
  // 請求地址
  url = "",
  // `data` 是作為請求主體被發(fā)送的數(shù)據(jù)
  // 在沒有設(shè)置 `transformRequest` 時盯孙,必須是以下類型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 瀏覽器專屬:FormData, File, Blob
  // - Node 專屬: Stream
  data = {},
  // "GET" "POST" ...
  method = defaultSetting.method,
  // `timeout` 指定請求超時的毫秒數(shù)(0 表示無超時時間)
  // 如果請求話費了超過 `timeout` 的時間敬尺,請求將被中斷
  timeout = defaultSetting.timeout,
  // `withCredentials` 表示跨域請求時是否需要使用憑證
  withCredentials = false,
  // `maxContentLength` 定義允許的響應(yīng)內(nèi)容的最大尺寸
  maxContentLength = 10000,
  // `responseType` 表示服務(wù)器響應(yīng)的數(shù)據(jù)類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType = "json",
  validateStatus = (status) => {
    return status >= defaultSetting.statusMin && status < defaultSetting.statusMax; // 默認的
  },
  // `onUploadProgress` 允許為上傳處理進度事件
  onUploadProgress = () => {},
  // `onDownloadProgress` 允許為下載處理進度事件
  onDownloadProgress = () => {},
  // `cancelToken` 指定用于取消請求的 cancel token
  // (查看后面的 Cancellation 這節(jié)了解更多)
  cancelToken,
  // `params` 是即將與請求一起發(fā)送的 URL 參數(shù)
  // 必須是一個無格式對象(plain object)或 URLSearchParams 對象
  params,
  // `auth` 表示應(yīng)該使用 HTTP 基礎(chǔ)驗證,并提供憑據(jù)
  // 這將設(shè)置一個 `Authorization` 頭对途,覆寫掉現(xiàn)有的任意使用 `headers` 設(shè)置的自定義 `Authorization`頭
  auth,
  baseUrl,
  // `headers` 是即將被發(fā)送的自定義請求頭
  headers = {},
  // 成功回調(diào)
  onSuccess = function (res) {},
  // 失敗回調(diào)
  onFail = function (res) {},
  // 全局回調(diào)(無論成功失敗, 都執(zhí)行)
  onFinally = function (res) {},
  // 全局成功回調(diào)
  onGlobalSuccess = function (res) {},
  // 全局失敗回調(diào)
  onGlobalFail = defaultSetting.onGlobalFail,
  // 成功條件計算方法
  computeSuccess = defaultSetting.computeSuccess
}) => {...}

這里為fetch.js導出的fetch方法的參數(shù)config.其中部分參數(shù)被使用于axios請求當中.部分參數(shù)被使用于請求后成功與失敗邏輯執(zhí)行.

  • 請求

 let _baseUrl = baseUrl || defaultBaseUrl
  // 如果有redirectUrl, 則覆蓋url
  url = _baseUrl + url;
  // 此處規(guī)定get請求的參數(shù)使用時放在data中替裆,如同post請求
  if (method == "GET") {
    let dataStr = "";
    // 將data參數(shù)用?&拼接
    dataStr = Object.entries(data).reduce((dataStr, value) => {
      dataStr = dataStr + `${value[0]}=${value[1]}&`
      return dataStr
    }, dataStr)
    if (dataStr !== "") {
      dataStr = dataStr.substr(0, dataStr.lastIndexOf("&"));
      url = url + "?" + dataStr;
    }
  }

此處拼接url

// config
let requestConfig = {
  url,
  method: method, // 默認是 get
  headers,
  params,
  data,
  timeout,
  withCredentials,
  auth,
  responseType, // 默認的
  onUploadProgress,
  onDownloadProgress,
  maxContentLength,
  cancelToken,
  validateStatus
}

用于aixos請求的config

// 發(fā)送請求
await axios(requestConfig).then(res => {
  // 允許實例自行計算成功條件
  const isSuccess = computeSuccess(res)
  const result = res.data
  // 成功碼默認為1, 根據(jù)后臺修改
  if (isSuccess) {
    onGlobalSuccess(result)
    onSuccess(result)
  } else {
    onGlobalFail(result)
    onFail(result)
  }
  onFinally(res)
})

發(fā)送請求, 通過computeSuccess計算出成功狀態(tài)碼, 運行對應(yīng)分支邏輯

  • 完整的fetch.js

import axios from 'axios'

import {
  notification
} from 'ant-design-vue'

const defaultBaseUrl = "http://192.168.0.1"; // 線上
// 默認請求配置
const defaultSetting = {
  // 請求方法
  method: 'GET',
  // 超時時間ms
  timeout: 600000,
  // res.code成功判定范圍
  statusMin: 200,
  statusMax: 99999,
  // 全局失敗回調(diào)
  onGlobalFail: function (res) {
    message(res.message || res.msg)
  },
  // 成功條件計算方法
  computeSuccess: function (res) {
    if (res.status > 299) return false
    return 1 === res.data.code
  }
}
// 服務(wù)器報錯提示款, 可以根據(jù)框架修改此函數(shù), msg為拋出信息
function message(msg) {
  notification.error({
    message: "服務(wù)器請求異常",
    description: "提示:" + msg
  })
}
export default async ({
  // 請求地址
  url = "",
  // `data` 是作為請求主體被發(fā)送的數(shù)據(jù)
  // 在沒有設(shè)置 `transformRequest` 時,必須是以下類型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 瀏覽器專屬:FormData, File, Blob
  // - Node 專屬: Stream
  data = {},
  // "GET" "POST" ...
  method = defaultSetting.method,
  // `timeout` 指定請求超時的毫秒數(shù)(0 表示無超時時間)
  // 如果請求話費了超過 `timeout` 的時間杯聚,請求將被中斷
  timeout = defaultSetting.timeout,
  // `withCredentials` 表示跨域請求時是否需要使用憑證
  withCredentials = false,
  // `maxContentLength` 定義允許的響應(yīng)內(nèi)容的最大尺寸
  maxContentLength = 10000,
  // `responseType` 表示服務(wù)器響應(yīng)的數(shù)據(jù)類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType = "json",
  validateStatus = (status) => {
    return status >= defaultSetting.statusMin && status < defaultSetting.statusMax; // 默認的
  },
  // `onUploadProgress` 允許為上傳處理進度事件
  onUploadProgress = () => {},
  // `onDownloadProgress` 允許為下載處理進度事件
  onDownloadProgress = () => {},
  // `cancelToken` 指定用于取消請求的 cancel token
  // (查看后面的 Cancellation 這節(jié)了解更多)
  cancelToken,
  // `params` 是即將與請求一起發(fā)送的 URL 參數(shù)
  // 必須是一個無格式對象(plain object)或 URLSearchParams 對象
  params,
  // `auth` 表示應(yīng)該使用 HTTP 基礎(chǔ)驗證营密,并提供憑據(jù)
  // 這將設(shè)置一個 `Authorization` 頭械媒,覆寫掉現(xiàn)有的任意使用 `headers` 設(shè)置的自定義 `Authorization`頭
  auth,
  baseUrl,
  // `headers` 是即將被發(fā)送的自定義請求頭
  headers = {},
  // 成功回調(diào)
  onSuccess = function (res) {},
  // 失敗回調(diào)
  onFail = function (res) {},
  // 全局回調(diào)(無論成功失敗, 都執(zhí)行)
  onFinally = function (res) {},
  // 全局成功回調(diào)
  onGlobalSuccess = function (res) {},
  // 全局失敗回調(diào)
  onGlobalFail = defaultSetting.onGlobalFail,
  // 成功條件計算方法
  computeSuccess = defaultSetting.computeSuccess
}) => {
  let _baseUrl = baseUrl || defaultBaseUrl
  // 如果有redirectUrl, 則覆蓋url
  url = _baseUrl + url;
  // 此處規(guī)定get請求的參數(shù)使用時放在data中,如同post請求
  if (method == "GET") {
    let dataStr = "";
    // 將data參數(shù)用?&拼接
    dataStr = Object.entries(data).reduce((dataStr, value) => {
      dataStr = dataStr + `${value[0]}=${value[1]}&`
      return dataStr
    }, dataStr)
    if (dataStr !== "") {
      dataStr = dataStr.substr(0, dataStr.lastIndexOf("&"));
      url = url + "?" + dataStr;
    }
  }
  // config
  let requestConfig = {
    url,
    method: method, // 默認是 get
    headers,
    params,
    data,
    timeout,
    withCredentials,
    auth,
    responseType, // 默認的
    onUploadProgress,
    onDownloadProgress,
    maxContentLength,
    cancelToken,
    validateStatus
  }
  // 發(fā)送請求
  await axios(requestConfig).then(res => {
    // 允許實例自行計算成功條件
    const isSuccess = computeSuccess(res)
    const result = res.data
    // 成功碼默認為1, 根據(jù)后臺修改
    if (isSuccess) {
      onGlobalSuccess(result)
      onSuccess(result)
    } else {
      onGlobalFail(result)
      onFail(result)
    }
    onFinally(res)
  })
};

api.js

import fetch from "./fetch.js";

export const api = {
  // 1. /login
  loginV2: config =>
    fetch({
      ...config,
      url: "/app/user/loginV2",
      onGlobalFail: function (res) {
        Modal.error({
          title: '登錄失敗',
          content: res.message || res.msg
        })
      },
      method: "POST"
    }),
  // 2. 獲取用戶  
  getUser: config =>
    fetch({
      ...config,
      url: "/app/user/findUser",
      method: "POST"
    }),
  ...
};

引入fetch.js, 所有接口添加到api對象中導出. 這里還可以對單個接口進行單獨的攔截. 比如所有g(shù)etUser方法對應(yīng)的接口不需要彈窗提示, 那么可以在這里修改getUser

  ...
  getUser: config =>
    fetch({
      ...config,
      onGlobalFail: () => {},
      url: "/app/user/findUser",
      method: "POST"
    }),
  ...

這樣, 如果這個接口在多個頁面都進行了調(diào)用, 則無需挨個修改了.

main.js

...
import {
  api
} from './api/api'

Vue.prototype.$api = api;
...

將api掛載到Vue原型

以上, 完成這行動作后, 我們就能通過this.$api這種方式調(diào)用接口了.

mock

開發(fā)時,我們經(jīng)常需要一些虛擬數(shù)據(jù).那么, 我們可以寫一個mock.js用于mock數(shù)據(jù).

mock.js

export const loginData = {
  "code": 1,
  "msg": "success",
  "data": {
    "userId": 1,
    "account": "2222222222",
    "role": 3,
    "password": null,
    "phone": "21121211221",
    "email": null,
    "unionId": null,
    "reName": null,
    "nickName": "xxx2",
    "accId": "dee2d504239649b6be54c1279926a4a7",
    "ytxAccount": "852b83a42d424f36bb9ef7d383acc08d",
    "headPic": "http://k1VoaL3.wlekjwqejklwq",
    "gender": 0,
    "age": null,
    "birthday": null,
    "constellation": null,
    "bloodType": null,
    "profession": null,
    "address": null,
    "contact": null,
    "studyCfNum": null,
    "teacherCfNum": null,
    "state": 0,
    "createTime": "2016-12-27 13:20:43",
    "lastUpdateTime": "2019-12-12 09:01:59",
    "lastLoginTime": "2020-01-02 17:50:14",
    "balance": null,
    "orgno": "00000768",
    "schoolName": null,
    "isBind": null,
    "onlineState": null,
    "userDevices": [],
    "classList": [],
    "clazzList": [],
    "children": [],
    "usrChildren": [],
    "fileStore": null,
    "popenId": "oFwyg4vN-Wv9LMwNKafeeeeeWexM",
    "topenId": "ohH6X5JSLwHzwYNewqewqecagVeaw"
  }
}

mockedApi

import fetch from "./fetch.js";
import {
  loginData
} from './mock.js'
export const api = {
  // 1. /login
  loginV2: config => config.onSuccess(loginData),
};

修改main.js中的api導入路徑為 mockedApi.js. 這樣, 當后臺接口開發(fā)完畢, 只要把路徑再改回去正式的接口這一個步驟, 就完成了mock數(shù)據(jù)到正式接口數(shù)據(jù)的變更, 十分便利.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末评汰,一起剝皮案震驚了整個濱河市纷捞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌被去,老刑警劉巖主儡,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惨缆,居然都是意外死亡糜值,警方通過查閱死者的電腦和手機丰捷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寂汇,“玉大人病往,你說我怎么就攤上這事〗景辏” “怎么了停巷?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長榕栏。 經(jīng)常有香客問我畔勤,道長,這世上最難降的妖魔是什么扒磁? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任庆揪,我火速辦了婚禮,結(jié)果婚禮上妨托,老公的妹妹穿的比我還像新娘缸榛。我一直安慰自己,他們只是感情好始鱼,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布仔掸。 她就那樣靜靜地躺著脆贵,像睡著了一般医清。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卖氨,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天会烙,我揣著相機與錄音,去河邊找鬼筒捺。 笑死柏腻,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的系吭。 我是一名探鬼主播五嫂,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肯尺!你這毒婦竟也來了沃缘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤则吟,失蹤者是張志新(化名)和其女友劉穎槐臀,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體氓仲,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡水慨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年得糜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晰洒。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡朝抖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谍珊,到底是詐尸還是另有隱情槽棍,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布抬驴,位于F島的核電站炼七,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏布持。R本人自食惡果不足惜豌拙,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望题暖。 院中可真熱鬧按傅,春花似錦、人聲如沸胧卤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枝誊。三九已至况芒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叶撒,已是汗流浹背绝骚。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留祠够,地道東北人压汪。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像古瓤,于是被迫代替她去往敵國和親止剖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355