uni-app token无感刷新并重新执行请求

创建request.js文件

export default {
	config: {
		baseURL: 'https://XXX.com/',//接口URL
		isRefreshing :true,
		subscribers : [],
		referToken() {
			let token = '';
			return new Promise((resolve, reject) => {
				let that = this
				if (!token) {
				  //获取用户信息
					uni.login({
						  provider: 'weixin', 
						  success: (res) => {
								//登陆成功的回调
								let obj = {
									code:res.code,
									appid:wx.getAccountInfoSync().miniProgram.appId
								}
								 uni.request({
									url: '请求tokenURL',
									data: obj,
									method: 'POST',
									header: {
										'content-type': 'application/x-www-form-urlencoded',
									},
									success: function(res) {
										const wx_openid = res.data.data.openid
										const token = res.data.data._token
										uni.setStorageSync("openid", openid)
										uni.setStorageSync("token", token)
										resolve(token)
										that.onAccessTokenFetched()//执行缓存中的请求
										   //延迟几秒再将刷新token的开关放开,不然偶尔还是会重复提交刷新token的请求
										   setTimeout(()=>{
											   that.isRefreshing = true
										   },3000)
										
									},
									fail: function(err) {
										console.log(err)
									}
								})
						  },
					})
				}
			})
		},
		// 响应拦截器
		beforeRequest(options = {}) {
			return new Promise((resolve, reject) => {
				if(!uni.getStorageSync("token")){
					if(this.isRefreshing){
						this.referToken()
					}
					this.isRefreshing = false
				}
				//请求的地址 = 上面设置的域名加上接口封装的地址
				options.url = this.baseURL + options.url;
				options.method = options.method || "POST";
				//添加请求头
				options.header = {
				  contentType: 'application/x-www-form-urlencoded',
				  token:!uni.getStorageSync("token") ? '' : uni.getStorageSync("token") 
				};
				resolve(options);
			});
		},
		// 刷新token的函数
		checkStatus(params) { 
			//这需要添加一个开关,防止重复请求
			if(this.isRefreshing){
				this.referToken()
			}
			this.isRefreshing = false; 
			// 将token刷新成功后的回调请求缓存
			const retryOriginalRequest = new Promise((resolve) => {
				this.addSubscriber(()=> {
					params.url = params.url.replace(this.baseURL, "");
					resolve(this.makeRequest(params))
				})	
			});
			return retryOriginalRequest;
			
			
		},
		//执行缓存中的请求
		onAccessTokenFetched() {
		    this.subscribers.forEach((callback)=>{
		        callback()
		    })
			this.subscribers = [];
		},
		// 缓存
		addSubscriber(callback) {
		    this.subscribers.push(callback)
		},
		// 请求拦截器
		handleResponse(data,params) {
			return new Promise((resolve, reject) => {
				const [err, res] = data; //此处data为接口返回值,请根据实际返回内容做出调整
				if (res) {
					if ( res.data.code == 20000) {
						return resolve(res.data);
					}
					if ( res.data.code == 40000) {
						uni.showToast({
							title:res.data.msg,
							icon:'none'
						})
					}
					if ( res.data.code == 40001) {
						console.log("请求失败")
						// 重新调起请求
						this.checkStatus(params).then(res=>{
							resolve(res)
						})
					}
					if(res.data.code == 40002){
						console.log("token过期")
						// 重新调起请求
						this.checkStatus(params).then(res=>{
							resolve(res)
						})
					}
				}
				if (err !== null) {
					return reject(err);
				} 
			})
		  
		},
		
		// 用于再次发起请求
		makeRequest(options = {}) {
			if(options.data !== undefined){
				options.data.openid == '' ? options.data.openid = uni.getStorageSync("openid") : ''
			}
			options.header.token ? options.header.token = uni.getStorageSync("token") : ''
			
			return this.beforeRequest(options).then((opt) => {
				return uni.request(opt);
			  })
			 .then((res) => this.handleResponse(res,options))
		}
	},
	// request 请求
	request(options = {}) {
	    return this.config.beforeRequest(options).then((opt) => {
			return uni.request(opt);
	      })
		 .then((res) => this.config.handleResponse(res,options))
	},
}

实际封装根据业务需求引入request.js文件即可
此处仅简单举例!!

import request from './request.js'
function postRequest(url, data){
    return request.request({
        url: url,  //接口地址
        method: 'post',
        data: data,
    })
}

module.exports = {
	postRequest
}
<think>好的,我现在需要帮助用户了解如何在uni-app中实现静默登录。根据用户提供的引用内容,他们可能遇到了微信授权登录的混乱教程,且提到了存放wgt文件的路径。静默登录通常指的是用户无感知的自动登录,比如通过本地存储的token或session进行验证,而不需要用户手动输入账号密码或进行授权操作。 首先,我需要回忆一下uni-app的登录机制。uni-app支持多端发布,所以静默登录的实现可能需要考虑不同平台的兼容性,尤其是微信小程序和H5。在微信小程序中,可以通过wx.login获取code,然后发送到后端换取openid和session_key,这属于一种静默登录,因为用户无需授权个人信息。但严格来说,这可能需要用户已使用过小程序,系统自动获取code。 接着,用户提到的引用[1]指出,关于微信授权登录的文章存在混乱,所以需要提供一个清晰的流程。静默登录的关键步骤可能包括:检测本地是否有有效token,如果有则直接登录,否则进行静默获取(如微信的code登录),失败后再转向显式授权。 然后,引用[2]提到了wgt文件的存放位置,这可能与资源更新有关,但和登录流程关系不大,可能用户误引用了相关内容,需要专注于登录部分的实现。 现在需要考虑uni-app中如何实现静默登录的具体步骤。首先,检查本地存储是否存在登录状态,比如uni.getStorageSync('token')。如果存在且未过期,则直接进入应用。如果不存在或已过期,则调用uni.login获取code,发送到后端服务器,后端通过code向微信服务器请求openid和session_key,生成返回自定义的token前端保存。如果静默登录失败(比如code无效),再引导用户进行显式授权,获取用户信息。 示例代码需要展示如何调用uni.login,处理返回的code,以及与后端的交互。同时,需要注意错误处理,比如网络请求失败的情况,需要捕获异常处理。 另外,需要考虑用户是否已经授权过,如果之前已经授权,静默登录可能可以直接获取信息;否则可能需要弹出授权窗口。但静默登录应尽量避免用户交互,所以优先使用不需要用户确认的方法,如wx.login。 最后,需要生成相关问题,比如静默登录与显式授权的区别、如何处理token过期、多端适配问题等。 总结步骤: 1. 检查本地token是否存在且有效。 2. 不存在则调用uni.login获取code。 3. 发送code到后端换取token。 4. 处理成功或失败的情况,失败则转显式登录。 5. 示例代码展示这个过程。</think>### 如何在 uni-app 中实现静默登录? #### 实现原理 静默登录的核心是通过 **本地存储的登录态**(如 token)或 **平台提供的无感登录能力**(如微信小程序`uni.login`获取 code)实现自动登录,无需用户手动授权或输入账号密码。关键流程如下: 1. **检测本地登录态**:启动时检查本地缓存是否存在有效 token 2. **静默获取身份标识**:若无有效 token,调用平台接口(如微信的`uni.login`)获取临时凭证 code 3. **后端验证**:将 code 发送至服务端,换取用户唯一标识(如 openid)生成 token[^1] 4. **失败降级策略**:若静默登录失败,引导用户进入显式授权流程 --- #### 示例代码 ```javascript // 1. 检查本地存储的 token let token = uni.getStorageSync('auth_token'); if (!token) { // 2. 静默获取微信 code uni.login({ provider: 'weixin', success: (loginRes) => { // 3. 发送 code 到服务端 uni.request({ url: 'https://api.example.com/auth/silent', method: 'POST', data: { code: loginRes.code }, success: (res) => { if (res.data.token) { uni.setStorageSync('auth_token', res.data.token); } else { // 4. 静默失败转显式登录 this.explicitLogin(); } } }); }, fail: () => this.explicitLogin() }); } // 显式授权登录 explicitLogin() { uni.getUserProfile({ desc: '获取信息用于登录', success: (res) => { // 处理授权信息... } }); } ``` --- #### 关键配置说明 1. **微信开放平台配置**:需配置 appid 和 AppSecret,确保 code 验证流程正常 2. **token 过期策略**:服务端应返回 token 有效期,前端定时刷新重新静默登录 3. **多端兼容**:通过`uni.getSystemInfo`判断平台,H5 端可使用 cookie 替代 code --- #### 注意事项 1. **用户首次使用**:静默登录只能获取 openid,需显式授权后才能获取昵称、头像等用户信息 2. **安全限制**:微信小程序 code 有效期 5 分钟,且只能使用一次 3. **网络容错**:弱网环境下需添加重试机制,避免直接阻塞用户
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值