callback和promise.all两种实现前端请求token过期时刷新token处理的解决模型

1. 需求分析

前台向后台请求数据,经常用到token。
token到了一定时期,后台会判定请求的token过期,需要重新请求。
但出现以下情况怎么办呢?
前台同时向后台发出n个带token的请求,但请求的token都是过期的,
每个请求都要先重新向后台刷新token,再回来执行刚刚的请求。
这就出现了一个问题:多次进行了不必要的请求token

2. 问题解决思路

实际买票模拟情景:一堆人同时去一个窗口买票
每个请求 = 去窗口买票
token过期 = 售票员不在了
刷新token = 去叫售票员回岗位

参考https://cloud.tencent.com/developer/article/1467376?from=singlemessage

思路分析:
大家都在排队买票,发现售票员不在了,没必要每个人都过去叫售票人买票,吩咐一个人过去就好了。
怎么才能知道有人去叫售票人了呢,可以通过写一张纸条的方式,上面写着“有人去叫售票员了”,这样就可以解决了。

3. Javascript下的两种实现模型

假设token请求需要1s,用setTimeout来模拟,前台请求模拟是传一个半径r过去,要求后台模拟计算它的面积并返回。

整个实现代码:https://github.com/Darbuly/HelloWorld/tree/master/tokens
(觉得还阔以的话记得点个星星哦亲~)

//统计数据
var tokenCount = 0
//模拟本地缓存的token
var tokenStorage = ''
var tokenLock = false
var reqQueue = []	//排队记录队列
//token请求模型
const getToken = (callback)=>{
	tokenCount++
	setTimeout(()=>{
		console.log(`累计token次数为${tokenCount}`)
		tokenStorage = 'tokenA'
		callback()
	},1000)
}

3.1 callback实现模型

function requestByCallback(r){
	console.log(`准备计算半径为${r.data}`)
	if(!tokenStorage){
		//如果token木有缓存
		if(!tokenLock){//如果没人去拿token
			//上锁
			tokenLock = true
			//请求
			getToken(()=>{
				//拿到了token
				//排队
				reqQueue.push(r)
				console.log(reqQueue)
				reqQueue.map(requestByCallback)
				reqQueue = []
				//解锁
				tokenLock = false
			})
		}else{
			//发现有人去拿token了
			reqQueue.push(r) //乖乖排队吧
		}
	}else{
		//有token了,就返回请求结果(假设这些请求都是求一个圆的面积)
		let S = 2*3.14*r.data*r.data
		r.callback(S)
	}
}

在这里插入图片描述

3.2 Promise实现模型

function requestByPromise(r){
	return new Promise((resolve,reject)=>{
		console.log(`准备计算半径为${r}`)
		if(!tokenStorage){
			//如果token木有缓存
			console.log(`半径为 ${r} 的无法计算,等待token请求`)
			if(!tokenLock){//如果没人去拿token
				//上锁
				tokenLock = true
				//请求
				getToken(()=>{
					//拿到了token
					//排队
					let p = ()=>requestByPromise(r).then((res)=>{
						resolve(res)//把队列形态的promise 的resolve的res 在这里完成 两级resolve
					})
					reqQueue.push(p)

					console.log('队列形态打印',reqQueue)
					reqQueue.forEach((v)=>{
						v()
					})//IE8以下不支持foreach
					let all = Promise.all(reqQueue)
					all.then((res)=>{
						console.log("看下队列形态的执行效果",res)	//看下队列形态的执行效果
					})
					reqQueue = []
					//解锁
					tokenLock = false
				})
			}else{
				//发现有人去拿token了
				 //乖乖排队吧
				let p = ()=>requestByPromise(r).then((res)=>{
					resolve(res)//把队列形态的promise 的resolve的res 在这里完成 两级resolve
				})
				reqQueue.push(p)
			}
		}else{
			//有token了,就返回请求结果(假设这些请求都是求一个圆的面积)
			let S = 2*3.14*r*r
			resolve(S)
		}
	})
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是一个可能的代码实现,供您参考: 首先,我们需要定义一个TokenInterceptor拦截器类,用于在每次请求接口检查Token是否过期: ```java public class TokenInterceptor implements Interceptor { private static final String TOKEN_KEY = "token"; private static final String AUTHORIZATION_HEADER = "Authorization"; private SharedPreferences mSharedPreferences; private ApiService mApiService; public TokenInterceptor(Context context, ApiService apiService) { mSharedPreferences = context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE); mApiService = apiService; } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); String token = mSharedPreferences.getString(TOKEN_KEY, ""); if (!TextUtils.isEmpty(token)) { request = request.newBuilder() .addHeader(AUTHORIZATION_HEADER, "Bearer " + token) .build(); } Response response = chain.proceed(request); if (response.code() == 401) { // Token过期,重新请求Token并重试请求 String newToken = getNewToken(); if (!TextUtils.isEmpty(newToken)) { // 更新Token并重试请求 mSharedPreferences.edit().putString(TOKEN_KEY, newToken).apply(); Request newRequest = request.newBuilder() .addHeader(AUTHORIZATION_HEADER, "Bearer " + newToken) .build(); response = chain.proceed(newRequest); } } return response; } private String getNewToken() { // 发送获取新Token请求,返回新Token Call<TokenResponse> call = mApiService.refreshToken(); try { Response<TokenResponse> response = call.execute(); if (response.isSuccessful()) { TokenResponse tokenResponse = response.body(); return tokenResponse.getToken(); } } catch (IOException e) { e.printStackTrace(); } return null; } } ``` 然后,在创建Retrofit实例,添加上述拦截器: ```java OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new TokenInterceptor(context, apiService)) .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build(); ``` 其中,apiService是一个定义了刷新Token接口的Retrofit接口。 最后,在请求A接口,如果遇到Token过期的情况,TokenInterceptor会自动发送请求获取新Token,并重新发送A接口请求: ```java Call<ResponseA> call = apiService.getAData(); call.enqueue(new Callback<ResponseA>() { @Override public void onResponse(Call<ResponseA> call, Response<ResponseA> response) { if (response.isSuccessful()) { // 请求成功 ResponseA responseA = response.body(); // 处理返回的数据 } else { // 请求失败 // 这里不需要处理401 Unauthorized错误,TokenInterceptor已经处理过了 } } @Override public void onFailure(Call<ResponseA> call, Throwable t) { // 请求失败 } }); ``` 以上就是一个简单的android token过期刷新并重新请求A接口的代码实现,仅供参考。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值