Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修改access token自动刷新逻辑,避免循环递归调用 #2115

Merged
merged 4 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) thro
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("重试达到最大次数【{}】", this.maxRetryTimes);
Expand Down Expand Up @@ -271,7 +271,7 @@ public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) thro
throw new WxRuntimeException("微信服务端异常,超出重试次数");
}

protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefresh) throws WxErrorException {
E dataForLog = DataUtils.handleDataWithSecret(data);

if (uri.contains("access_token=")) {
Expand All @@ -291,9 +291,11 @@ protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E
if (WxConsts.ACCESS_TOKEN_ERROR_CODES.contains(error.getErrorCode())) {
// 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
this.configStorage.expireAccessToken();
if (this.getWxCpConfigStorage().autoRefreshToken()) {
if (this.getWxCpConfigStorage().autoRefreshToken() && !doNotAutoRefresh) {
log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
//下一次不再自动重试
//当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出
return this.executeInternal(executor, uri, data, true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public Object[][] getService() {

@Override
public synchronized <T, E> T executeInternal(
RequestExecutor<T, E> executor, String uri, E data)
RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefresh)
throws WxErrorException {
log.info("Executed");
throw new WxErrorException("something");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
package me.chanjar.weixin.cp.api.impl;

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.HttpType;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
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;

/**
* <pre>
Expand Down Expand Up @@ -35,6 +48,61 @@ public void testJsCode2Session() throws WxErrorException {

@Test
public void testGetProviderToken() throws WxErrorException {
assertThat(this.wxService.getProviderToken("111","123")).isNotNull();
assertThat(this.wxService.getProviderToken("111", "123")).isNotNull();
}


@Test
public void testExecuteAutoRefreshToken() throws WxErrorException, IOException {
//测试access token获取时的重试机制
WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
BaseWxCpServiceImpl service = new BaseWxCpServiceImpl() {
@Override
public Object getRequestHttpClient() {
return null;
}

@Override
public Object getRequestHttpProxy() {
return null;
}

@Override
public HttpType getRequestType() {
return null;
}

@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
return "模拟一个过期的access token:" + System.currentTimeMillis();
}

@Override
public void initHttp() {

}

@Override
public WxCpConfigStorage getWxCpConfigStorage() {
return config;
}
};
config.setAgentId(1);
service.setWxCpConfigStorage(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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) thro
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);
Expand Down Expand Up @@ -238,7 +238,7 @@ public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) thro
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=")) {
Expand Down Expand Up @@ -271,9 +271,11 @@ private <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E d
} 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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@

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;

Expand Down Expand Up @@ -101,6 +112,35 @@ public void testGet() {
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() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) thro
int retryTimes = 0;
do {
try {
return this.executeInternal(executor, uri, data);
return this.executeInternal(executor, uri, data, false);
} catch (WxErrorException e) {
WxError error = e.getError();
// -1 系统繁忙, 1000ms后重试
Expand Down Expand Up @@ -370,7 +370,7 @@ public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) thro
throw new WxRuntimeException("微信服务端异常,超出重试次数");
}

protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefresh) throws WxErrorException {
E dataForLog = DataUtils.handleDataWithSecret(data);

if (uri.contains("access_token=")) {
Expand Down Expand Up @@ -399,9 +399,11 @@ protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E
} finally {
lock.unlock();
}
if (this.getWxMpConfigStorage().autoRefreshToken()) {
if (this.getWxMpConfigStorage().autoRefreshToken() && !doNotAutoRefresh) {
log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
//下一次不再自动重试
//当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出
return this.executeInternal(executor, uri, data, true);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package me.chanjar.weixin.mp.api;

import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
import org.testng.annotations.*;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
Expand All @@ -23,7 +23,7 @@ public Object[][] getService() {

@Override
public synchronized <T, E> T executeInternal(
RequestExecutor<T, E> executor, String uri, E data)
RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefresh)
throws WxErrorException {
log.info("Executed");
throw new WxErrorException("something");
Expand All @@ -37,7 +37,7 @@ public synchronized <T, E> T executeInternal(

@Test(dataProvider = "getService", expectedExceptions = RuntimeException.class)
public void testRetry(WxMpService service) throws WxErrorException {
service.execute(null, (String)null, null);
service.execute(null, (String) null, null);
}

@Test(dataProvider = "getService")
Expand All @@ -48,7 +48,7 @@ public void testRetryInThreadPool(final WxMpService service) throws InterruptedE
try {
System.out.println("=====================");
System.out.println(Thread.currentThread().getName() + ": testRetry");
service.execute(null, (String)null, null);
service.execute(null, (String) null, null);
} catch (WxErrorException e) {
throw new WxRuntimeException(e);
} catch (RuntimeException e) {
Expand Down
Loading