api调用实例
...
methed: {
...
// 根据账户查询用户的api
async getUser() {
const {account} = this
const data = {
account
}
await this.$api
.getUsers({
data,
// 成功回调
onSuccess: res => {
// ?. 为选择链式调用, 如果data为null, 不会报错,会返回undefined, 需要polify
let list = res ?.data ?.pageData || []
// 处理数据
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开关, await 调用接口请求函数, 可以在请求完成后, 再继续运行程序, 关闭loading开关
fetch.js封装过程
-
axios
import axios from 'axios'
axios 是一个基于 promise 用于浏览器和 nodejs 的 http 客户端,本身具有以下特征:
- 从浏览器中创建 XMLHttpRequest
- 从 nodejs 发出 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防止 CSRF / XSRF
axios 对vue有非常高的支持度, 很多vue项目都是用axios作为api请求插件. 网上也有非常多对axios进行二次封装的文章, 笔者也是参考了总多封装方法, 最后自己修改设计了这套自用模板. axios的具体是用方法此处就不详细介绍, 如果对axios还不是非常熟悉, 可以直接访问文档进行学习.
除了axios, 也还有fetch等其他api请求方案, 也可以根据不同的请求方案, 对fetch.js文件进行修改, 以满足需求.
-
message
import {
notification
} from 'ant-design-vue'
...
function message(msg) {
notification.error({
message: "服务器请求异常",
description: "提示:" + msg
})
}
message 模块是用于接口提示信息抛出的模块. 比如, 一个修改数据的接口, 在接口请求成功后, 返回成功code. 此时就可以用message弹出一个提示信息, 提示用户修改成功. 请求失败也是同理, 可以抛出失败原因等.可以根据项目, 修改对应的组件. 例如element的 messageBox等.
-
defaultSetting
// 默认请求配置
const defaultSetting = {
// 请求方法
method: 'GET',
// 超时时间ms
timeout: 600000,
// res.code成功判定范围
statusMin: 0,
statusMax: 99999,
// 全局失败回调
onGlobalFail: function (res) {
message(res.message || res.msg)
},
// 成功条件计算方法
computeSuccess: function (res) {
if (res.status > 299) return false
return 1 === res.data.code
}
}
defaultSetting默认设置, 这里可以配置一些默认参数
method 请求方法(GET, PSOT, ...)
timeout 请求超时判断时间ms
statusMin, statusMax 请求返回状态码判定成功的范围,例如min设置为200, max设置为399. 则403, 404等状态码的请求会被判定为请求失败, 执行请求失败分支.(这个状态码配置的是aixos插件的成功判断, 由于笔者自己写了成功与失败的分支, 所以这里设置了0-99999都为成功, 即所有情况下都把结果返回, 由自定义的方法去判断请求是否成功)
onGlobalFail [Function] 全局失败回调. 这个方法可以接受一个res的参数,即请求结果. 当自定义方法判定请求失败时执行.此方法默认为全局方法, 会应用于所有请求. 这个方法默认为使用之前定义的message方法, 弹出一个提示框, 展示失败信息. 可以在调用具体接口时覆盖此方法.
computeSuccess 此方法用于计算成功状态,接受res参数, 即请求结果. 此方法返回一个boolean值, true时执行请求成功逻辑, false时执行请求失败逻辑.
-
config
export default async ({
// 请求地址
url = "",
// `data` 是作为请求主体被发送的数据
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data = {},
// "GET" "POST" ...
method = defaultSetting.method,
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout = defaultSetting.timeout,
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials = false,
// `maxContentLength` 定义允许的响应内容的最大尺寸
maxContentLength = 10000,
// `responseType` 表示服务器响应的数据类型,可以是 '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 这节了解更多)
cancelToken,
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params,
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
auth,
baseUrl,
// `headers` 是即将被发送的自定义请求头
headers = {},
// 成功回调
onSuccess = function (res) {},
// 失败回调
onFail = function (res) {},
// 全局回调(无论成功失败, 都执行)
onFinally = function (res) {},
// 全局成功回调
onGlobalSuccess = function (res) {},
// 全局失败回调
onGlobalFail = defaultSetting.onGlobalFail,
// 成功条件计算方法
computeSuccess = defaultSetting.computeSuccess
}) => {...}
这里为fetch.js导出的fetch方法的参数config.其中部分参数被使用于axios请求当中.部分参数被使用于请求后成功与失败逻辑执行.
-
请求
let _baseUrl = baseUrl || defaultBaseUrl
// 如果有redirectUrl, 则覆盖url
url = _baseUrl + url;
// 此处规定get请求的参数使用时放在data中,如同post请求
if (method == "GET") {
let dataStr = "";
// 将data参数用?&拼接
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
// 发送请求
await axios(requestConfig).then(res => {
// 允许实例自行计算成功条件
const isSuccess = computeSuccess(res)
const result = res.data
// 成功码默认为1, 根据后台修改
if (isSuccess) {
onGlobalSuccess(result)
onSuccess(result)
} else {
onGlobalFail(result)
onFail(result)
}
onFinally(res)
})
发送请求, 通过computeSuccess计算出成功状态码, 运行对应分支逻辑
-
完整的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,
// 全局失败回调
onGlobalFail: function (res) {
message(res.message || res.msg)
},
// 成功条件计算方法
computeSuccess: function (res) {
if (res.status > 299) return false
return 1 === res.data.code
}
}
// 服务器报错提示款, 可以根据框架修改此函数, msg为抛出信息
function message(msg) {
notification.error({
message: "服务器请求异常",
description: "提示:" + msg
})
}
export default async ({
// 请求地址
url = "",
// `data` 是作为请求主体被发送的数据
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data = {},
// "GET" "POST" ...
method = defaultSetting.method,
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout = defaultSetting.timeout,
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials = false,
// `maxContentLength` 定义允许的响应内容的最大尺寸
maxContentLength = 10000,
// `responseType` 表示服务器响应的数据类型,可以是 '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 这节了解更多)
cancelToken,
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params,
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
auth,
baseUrl,
// `headers` 是即将被发送的自定义请求头
headers = {},
// 成功回调
onSuccess = function (res) {},
// 失败回调
onFail = function (res) {},
// 全局回调(无论成功失败, 都执行)
onFinally = function (res) {},
// 全局成功回调
onGlobalSuccess = function (res) {},
// 全局失败回调
onGlobalFail = defaultSetting.onGlobalFail,
// 成功条件计算方法
computeSuccess = defaultSetting.computeSuccess
}) => {
let _baseUrl = baseUrl || defaultBaseUrl
// 如果有redirectUrl, 则覆盖url
url = _baseUrl + url;
// 此处规定get请求的参数使用时放在data中,如同post请求
if (method == "GET") {
let dataStr = "";
// 将data参数用?&拼接
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
}
// 发送请求
await axios(requestConfig).then(res => {
// 允许实例自行计算成功条件
const isSuccess = computeSuccess(res)
const result = res.data
// 成功码默认为1, 根据后台修改
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对象中导出. 这里还可以对单个接口进行单独的拦截. 比如所有getUser方法对应的接口不需要弹窗提示, 那么可以在这里修改getUser
...
getUser: config =>
fetch({
...config,
onGlobalFail: () => {},
url: "/app/user/findUser",
method: "POST"
}),
...
这样, 如果这个接口在多个页面都进行了调用, 则无需挨个修改了.
main.js
...
import {
api
} from './api/api'
Vue.prototype.$api = api;
...
将api挂载到Vue原型
以上, 完成这行动作后, 我们就能通过this.$api这种方式调用接口了.
mock
开发时,我们经常需要一些虚拟数据.那么, 我们可以写一个mock.js用于mock数据.
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. 这样, 当后台接口开发完毕, 只要把路径再改回去正式的接口这一个步骤, 就完成了mock数据到正式接口数据的变更, 十分便利.