🎨 #2115 优化公众号、小程序、企业微信的access token自动刷新逻辑,避免循环递归调用

This commit is contained in:
hywr
2021-05-20 14:23:26 +08:00
committed by GitHub
parent dfb02eac38
commit 62a3931aee
8 changed files with 200 additions and 28 deletions

View File

@ -207,7 +207,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
int retryTimes = 0;
do {
try {
return this.executeInternal(executor, uri, data);
return this.executeInternal(executor, uri, data, false);
} catch (WxErrorException e) {
if (retryTimes + 1 > this.maxRetryTimes) {
log.warn("重试达到最大次数【{}】", maxRetryTimes);
@ -238,7 +238,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
throw new WxRuntimeException("微信服务端异常,超出重试次数");
}
private <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
private <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefreshToken) throws WxErrorException {
E dataForLog = DataUtils.handleDataWithSecret(data);
if (uri.contains("access_token=")) {
@ -271,9 +271,11 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
} finally {
lock.unlock();
}
if (this.getWxMaConfig().autoRefreshToken()) {
if (this.getWxMaConfig().autoRefreshToken() && !doNotAutoRefreshToken) {
log.warn("即将重新获取新的access_token错误代码{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
//下一次不再自动重试
//当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出
return this.executeInternal(executor, uri, data, true);
}
}

View File

@ -2,14 +2,25 @@ package cn.binarywang.wx.miniapp.api.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.test.ApiTestModule;
import com.google.inject.Inject;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxMpErrorMsgEnum;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import org.apache.commons.lang3.StringUtils;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertTrue;
@ -101,6 +112,35 @@ public class WxMaServiceImplTest {
public void testExecute() {
}
@Test
public void testExecuteAutoRefreshToken() throws WxErrorException, IOException {
//测试access token获取时的重试机制
WxMaServiceImpl service = new WxMaServiceImpl() {
@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
return "模拟一个过期的access token:" + System.currentTimeMillis();
}
};
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid("1");
service.setWxMaConfig(config);
RequestExecutor<Object, Object> re = mock(RequestExecutor.class);
AtomicInteger counter = new AtomicInteger();
Mockito.when(re.execute(Mockito.anyString(), Mockito.any(), Mockito.any())).thenAnswer(invocation -> {
counter.incrementAndGet();
WxError error = WxError.builder().errorCode(WxMpErrorMsgEnum.CODE_40001.getCode()).errorMsg(WxMpErrorMsgEnum.CODE_40001.getMsg()).build();
throw new WxErrorException(error);
});
try {
Object execute = service.execute(re, "http://baidu.com", new HashMap<>());
Assert.assertTrue(false, "代码应该不会执行到这里");
} catch (WxErrorException e) {
Assert.assertEquals(WxMpErrorMsgEnum.CODE_40001.getCode(), e.getError().getErrorCode());
Assert.assertEquals(2, counter.get());
}
}
@Test
public void testGetWxMaConfig() {
}