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 是一個基于 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ù)的變更, 十分便利.