大家好😊,我叫天黑黑,默默在掘金潜水很长时间了,今天刚刚提测了小程序,下午在掘金划划水(嘘...),突发奇想,想写一篇热乎的文章(第一次写文章...😋)
前两周被通知要做一个钉钉小程序,由于公司的技术栈是vue,就选择了uni-app 作为小程序的前端框架
项目目录
...
├──src
│ ├──api // api文件夹
│ ├──modules // 分模块的请求地址
│ ...
│ ├──index.js // modules的整合
│ ├──request.js // 请求封装
| ...
│ ├──config // 根据不同环境配置的请求地址
....
项目中按模块划分了请求,只要在 modules 文件夹中新增模块的请求js文件(例如:登录模块:新增 modules/login.js )
在 api/index.js 对 modules 进行统一整合。
api/inedx.js
const modulesFiles = require.context('./modules', true, /\.js$/)
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
const value = modulesFiles(modulePath)
modules = {
...modules,
...value.default
}
return modules
}, {})
export default {
...modules
}
使用webpack中的 require.context 获取上下文,不用写过多的import来导入模块
例:base.js
/**
* 请求配置项:默认值
* url = '',
* method = 'GET',
* BASE_API = env_config.BASE_API,
* headers = {'Content-Type': 'application/x-www-form-urlencoded'}, // 默认
* dataType = 'json', // 支持json、text、base64
* timeout = 30000 // 默认 30000
* loading = true,
* loadingText = '加载中...',
* token = true
**/
import HTTP from '../request.js';
const BASE_API = {
// 获取token
API_TOKEN() {
return HTTP({
url: `/api/auth/token`,
token: false,
loading: false
})
},
// 获取用户信息
API_USER_INFO(data) {
return HTTP({
url: '/api/auth/userinfo',
loading: false
}, data)
}
}
export default BASE_API
config/
config文件夹,是通过 process.env.NODE_ENV 来配置不同环境的全局变量,例如 BaseURL、小程序ID等...
api/request.js
这是对 dd.httpRequest 的二次封装,如下:
const env_config = require('../config/index.js')
import store from '../store/index.js'
let isRefresh = false // 是否在请求新的token
const http = (option, data) => {
let {
url = '',
method = 'GET',
BASE_API = env_config.BASE_API,
headers = {'Content-Type': 'application/x-www-form-urlencoded'}, // 默认
dataType = 'json', // 支持json、text、base64
timeout = 3000000, // 默认 30000
loading = true,
loadingText = '加载中...',
token = true
} = option
// 1.2 Promise
return new Promise(async (resolve, reject) => {
// 是否需要 请求loading
if(loading) {
dd.showLoading({
content: loadingText,
});
}
// 是否需要token
if(token) {
let access_token = dd.getStorageSync({ key: 'access_token' }).data
if(!access_token) {
// 具体获取token的请求,在store中
await store.dispatch('getAccessToken').then(res => {
access_token = res.token
})
}
headers = {
...headers,
"Authorization": `Bearer ${access_token}`
}
}
method = method.toUpperCase();
dd.httpRequest({
url: BASE_API + url,
method: method,
headers: headers,
data: data,
timeout: timeout,
dataType: dataType,
success: function(res) {
if(res.status === 200) {
resolve(res.data)
} else {
dd.showToast({
type: 'fail',
content: res.data.msg,
duration: 3000
});
}
},
fail: async function(res) {
// 如果接口返回 401 无权限,再请求一次token,并在resolve中返回本次请求
if(res.status === 401) {
if(!isRefresh) {
isRefresh = true
await store.dispatch('getAccessToken').then(res => {
if(res.code === '0') {
resolve(http(option, data))
} else {
dd.showToast({
type: 'fail',
content: res.msg,
duration: 3000,
success:() => {
dd.navigateTo({
url: '/pages/noToken'
})
}
});
}
}).catch(err => {
dd.showToast({
type: 'fail',
content: err.msg,
duration: 3000,
success:() => {
dd.navigateTo({
url: '/pages/noToken'
})
}
});
}).finally(() => {
isRefresh = false
})
}
} else {
reject(res)
}
},
complete: function(res) {
dd.hideLoading();
}
});
})
};
export default http
这里用的钉钉小程序的api,可以换成uniapp的api,同样适用;
在main.js中:
import http from './api/index.js';
Vue.prototype.$HTTP = http
如何使用
在项目中使用如下:
const data = {
userId: 'test'
}
this.$HTTP.API_USER_INFO(data).then(res => {
...
}).catch(() => {
...
}).finally(() => {
...
})