fix(qrLogin): 优化小程序码Token错误处理与缓存清理

- 新增access_token对应Redis键,保持与WxService一致
- 获取access_token失败时添加缓存清理操作
- 生成小程序码API返回token相关错误时清理缓存
- 异常捕获时也进行access_token缓存清理,防止token问题
- 增加判断token相关错误码的方法,明确常见微信API错误码
- 实现清理access_token缓存方法,包含异常日志处理
This commit is contained in:
2026-04-11 07:44:34 +08:00
parent 1d5b65bcc0
commit 7aaf25c1ac

View File

@@ -126,11 +126,16 @@ public class QrLoginServiceImpl implements QrLoginService {
* @return 小程序码图片Base64字符串 * @return 小程序码图片Base64字符串
*/ */
private String generateMiniprogramQrCode(String token, Integer tenantId) { private String generateMiniprogramQrCode(String token, Integer tenantId) {
// 构建 access_token 的 Redis key与 WxService 保持一致)
String accessTokenKey = "WX_ACCESS_TOKEN:" + (tenantId != null ? tenantId : 10048);
try { try {
// 获取小程序access_token // 获取小程序access_token
String accessToken = wxService.getAccessToken(tenantId); String accessToken = wxService.getAccessToken(tenantId);
if (StrUtil.isBlank(accessToken)) { if (StrUtil.isBlank(accessToken)) {
log.warn("获取小程序access_token失败跳过生成小程序码"); log.warn("获取小程序access_token失败跳过生成小程序码,将清理缓存");
// 获取失败时清理缓存,下次会重新获取
clearAccessTokenCache(accessTokenKey, tenantId);
return null; return null;
} }
@@ -166,7 +171,18 @@ public class QrLoginServiceImpl implements QrLoginService {
// 检查是否返回JSON错误微信API错误时会返回JSON // 检查是否返回JSON错误微信API错误时会返回JSON
if (imageBytes.length < 100 && new String(imageBytes).startsWith("{")) { if (imageBytes.length < 100 && new String(imageBytes).startsWith("{")) {
JSONObject errorResult = JSON.parseObject(new String(imageBytes)); JSONObject errorResult = JSON.parseObject(new String(imageBytes));
log.error("生成小程序码API返回错误: {}", errorResult); Integer errCode = errorResult.getInteger("errcode");
String errMsg = errorResult.getString("errmsg");
// 判断是否是 token 相关错误,需要清理缓存
boolean shouldClearCache = isTokenRelatedError(errCode, errMsg);
if (shouldClearCache) {
log.error("生成小程序码API返回token相关错误[{}:{}],将清理缓存", errCode, errMsg);
clearAccessTokenCache(accessTokenKey, tenantId);
} else {
log.error("生成小程序码API返回错误[{}:{}],不清理缓存", errCode, errMsg);
}
return null; return null;
} }
@@ -176,10 +192,55 @@ public class QrLoginServiceImpl implements QrLoginService {
return "data:image/png;base64," + base64Image; return "data:image/png;base64," + base64Image;
} catch (Exception e) { } catch (Exception e) {
log.error("生成小程序码异常: {}", e.getMessage(), e); log.error("生成小程序码异常: {}", e.getMessage(), e);
// 异常时也清理缓存,以防是 token 问题
clearAccessTokenCache(accessTokenKey, tenantId);
return null; return null;
} }
} }
/**
* 判断是否是 token 相关的错误码,需要清理缓存
* 常见微信 API 错误码:
* - 40001: 获取access_token时AppSecret错误
* - 40013: appid无效
* - 40125: appsecret无效
* - 42001: access_token超时
* - 42002: refresh_token超时
* - 42003: code超时
* - 44002: post body太长
* - 44003: 图片太大
* - 41002: appid不正确
* - 41008: 缺少access_token参数
*/
private boolean isTokenRelatedError(Integer errCode, String errMsg) {
if (errCode == null) {
return false;
}
// token 相关错误码
return errCode == 40001 // AppSecret错误
|| errCode == 40013 // appid无效
|| errCode == 40125 // appsecret无效
|| errCode == 42001 // access_token超时
|| errCode == 42002 // refresh_token超时
|| errCode == 42003 // code超时
|| errCode == 41002 // appid不正确
|| errCode == 41008 // 缺少access_token参数
|| errCode == 40014 // 不合法的access_token
|| errCode == 40097; // invalid page
}
/**
* 清理 access_token 缓存
*/
private void clearAccessTokenCache(String accessTokenKey, Integer tenantId) {
try {
redisUtil.delete(accessTokenKey);
log.info("清理微信access_token缓存[{}], tenantId={}", accessTokenKey, tenantId);
} catch (Exception e) {
log.error("清理access_token缓存失败: {}", e.getMessage());
}
}
@Override @Override
public QrLoginStatusResponse checkQrLoginStatus(String token) { public QrLoginStatusResponse checkQrLoginStatus(String token) {
if (StrUtil.isBlank(token)) { if (StrUtil.isBlank(token)) {