uniapp 封装请求,实现无痛刷新token

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文件。

uniapp 封装请求,实现无痛刷新token_第1张图片

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
	 });
})

 

你可能感兴趣的:(uniapp,uni-app,javascript)