uniapp封装请求,使用的是DCloud插件市场的插件:《干脆清晰的request请求库 支持各种拦截与回调 上传下载》,感谢作者!
我下载的是:
更新日期:2020-06-03
版本:4.1.0
为了实现批量上传图片,我略微改动了下插件中的common.js文件:
//common.js
export async function requestConfig(ins, options) {
// JSON.parse(JSON.stringify(options.header || ins.header))
// 注意: header默认采用了整体取代的方式,options设置了header,ins中的header会整个丢弃
const header = Object.assign({}, (options.header || ins.header))//options.header=null才会使用ins.header,两者都需要是{}或null
const baseUrl = options.baseUrl || ins.baseUrl //options.baseUrl=''或0,才会使用ins.baseUrl
// config
let config = {
url: baseUrl + options.url,
header: header
}
let _cg = null
if (ins.requestInterceptor) {//请求拦截器
try{
const _options = JSON.parse(JSON.stringify(Object.assign({}, (options||{}), config)))//JSON.parse(JSON.stringify())目的是实现深度拷贝
// _cg is tha same object of _options
_cg = await ins.requestInterceptor(_options)
}catch(e){
return {mypReqToCancel: true, error: e}
}
// no need to reqeust
if (_cg.mypReqToCancel) {
return _cg
}
// we could also change the url and header in interceptors
config.url = _cg.url
config.header = _cg.header
}
const type = options.type || "request"
// config detail, remove unneeded props
if (type === "request") {
config["data"] = _cg.data || {}
config["method"] = _cg.method || "GET"
config["dataType"] = _cg.dataType || "json"
config["responseType"] = _cg.responseType || "text"
} else if (type === "upload") {
config['files'] = _cg.files //为实现批量上传图片,增加了这句话
config['filePath'] = _cg.filePath
config['name'] = _cg.name
config["method"] = _cg.method || "POST"
config['formData'] = _cg.formData || {}
// fileType for alipay
config["fileType"] = _cg.fileType || "image"
// config.header['content-type'] = 'multipart/form-data;charset=UTF-8'
delete config.header['Content-Type']
delete config.header['content-type']
} // download need nothing else to config
return config
}
我在项目下创建了一个api目录,放置下载的插件,同时新建了request.js和index.js文件。
request.js中封装了带有拦截器的请求,实现:
(1)在请求拦截器中,判断该请求是否需要token,需要则在header中加上token。最初的获取token请求写在登陆成功的回调函数中了。
(2)在响应拦截器中,判断token是否过期了,过期则刷新token,并继续之前的请求。
// 引入 Request
import Request from './myp-request/index.js'
// 设置 通用的 baseUrl 以及 header
const baseUrl = 'http://xxx.xx.x.xx/WebAPI'; //本机
const config = {
baseUrl: baseUrl,
header: {
"content-type": "application/x-www-form-urlencoded"
}
}
// 设置自己的请求拦截器,必须加上 `async`
// 请求前的拦截,比如是否登录/过期/刷新token/...
const reqInterceptor = async (options) => {
// 必须返回一个 Object
// 拦截请求:return {mypReqToCancel: true, ...}
// TODO: 添加任意拦截逻辑
if (options.authToken) {
let token = uni.getStorageSync('token');
options.header.Authorization = 'Bearer ' + token;
//console.log(options);
return options;
}
//console.log(options);
return options
}
// 设置自己的响应拦截器
// 统一对返回的数据进行整理,方便接口统一使用
// conf是您api的options信息,一般情况下您只需要用到您自定义的标记字段
const resInterceptor = (response, conf = {}) => {
// 必须返回你需要处理的数据,将会进入resolve(then中处理)
// 如果需要reject,需要设置mypReqToReject:true,还可以携带自己定义的任何提示内容(catch中处理)
// uni.request进入fail也会进入该拦截器(为了统一处理逻辑),这个时候的response参数为{mypFail: true, response: fail info}。fail时不管返回啥,都进入reject(catch)
//token过期,刷新token,重新请求当前任务
if (response.statusCode == 401 || response.data.code == 402) {
//console.log('token过期了:'+Date.now())
let response = doRequest(conf)
return response
}
if (response.mypFail) {
//console.log(response.response)
return response.response
}
// 请求被拦截时也会进入该回掉(为了统一处理逻辑),这个时候的response参数为{mypCancel: true, response: cancel info}。cancel时不管返回啥,都进入reject(catch)
if (response.mypCancel) {
return response.response
}
return response
}
// 实例化请求器
// 您可以根据需要实例化多个请求器
const req = new Request(config, reqInterceptor, resInterceptor)
//刷新token并继续之前请求
async function doRequest(config) {
//刷新token
const value = uni.getStorageSync('uerInfo');
//console.log(value);
const res = await req.request({
url: '/api/token',
method: 'POST',
data: {
username: value.USERNAME,
password: value.PASSWORD,
grant_type: 'password'
},
authToken: false
})
//console.log(res);
uni.setStorageSync('token', res.data.access_token);
//重新请求当前任务
//console.log(config)
let url = config.url.replace(baseUrl, '');
var postData = {
url: url,
method: config.method,
data: config.data,
authToken: true
}
return await req.request(postData)
}
export default req
index.js中封装了各个请求实例:
import request from './request.js'
/**
* 用户登录
* @param {Object} data
* authToken:是否需要token
*/
export function userLogin(data) {
return request.request({
url: '/api/Login',
method: 'POST',
data: data,
authToken: false
})
}
/**
* 获取token
* @param {Object} data
*/
export function getToken(data) {
return request.request({
url: '/api/token',
method: 'POST',
data: data,
authToken: false
})
}
/**
* 上传图片及文字信息
* @param {Object} files 图片信息
* @param {Object} data 随图片一同上传的文字信息
*/
export function uploadInfo(files, data) {
return request.request({
url: '/api/uploadInfo',
files: files,
formData: data,
type: 'upload',
authToken: true
})
}
关于批量上传图片:
//存储图片地址的变量
this.imageList=[];
//选择图片
uni.chooseImage({
sourceType: ['camera'],//album,camera
sizeType: ['compressed'],
count: 6 - this.imageList.length,
success: res => {
this.imageList = this.imageList.concat(res.tempFilePaths);
}
});
//在上传图片前,需要略微处理下数据
let imgs= this.imageList.map((value, index) => {
return {
name: 'image' + index,
uri: value
};
});
//随图片一同上传的文字信息
let formData={
title:'上传测试',
content:'为了说明formData就是普通的对象'
}
//上传
uploadInfo(imgs,formData).then(res =>
{
if (res.statusCode === 200) {
console.log('上传成功!');
}
}).catch(err => {
uni.showModal({
content: err,
showCancel: false
});
})