Просмотр исходного кода

fix(backend): 微信安全检测改用stable_token接口避免'not latest'冲突

getAccessToken()默认调用/cgi-bin/stable_token,token由独占改为共享,彻底解决多实例40001错误

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Xiaogang Liao 3 месяцев назад
Родитель
Сommit
8dad750b11
1 измененных файлов с 50 добавлено и 11 удалено
  1. 50 11
      cfc-backend/src/main/java/com/etotem/cfc/service/WechatService.java

+ 50 - 11
cfc-backend/src/main/java/com/etotem/cfc/service/WechatService.java

@@ -65,9 +65,9 @@ public class WechatService implements WechatServiceInterface {
 
     private final RestTemplate restTemplate = new RestTemplate();
 
-    // ===== access_token 缓存 =====
-    private volatile String cachedAccessToken;
-    private volatile long tokenExpireTime;
+    // ===== stable access_token 缓存(独立缓存,用于避免"not latest"冲突)=====
+    private volatile String cachedStableAccessToken;
+    private volatile long stableTokenExpireTime;
 
     /**
      * 判断是否测试模式
@@ -213,6 +213,7 @@ public class WechatService implements WechatServiceInterface {
 
     /**
      * 获取access_token(带缓存,TTL 7000秒,提前200秒刷新)
+     * 默认使用stable_token API,避免多实例/多调用导致的"not latest"冲突
      */
     public String getAccessToken() {
         // 测试模式:每次都重新获取
@@ -220,23 +221,61 @@ public class WechatService implements WechatServiceInterface {
             return doGetAccessToken();
         }
 
+        return getStableAccessToken();
+    }
+
+    /**
+     * 获取stable access_token(带缓存)
+     * 使用 /cgi-bin/stable_token 接口,token有效期7200秒,可被所有实例共享使用
+     * 彻底解决"access_token is invalid or not latest"错误
+     */
+    private String getStableAccessToken() {
         long now = System.currentTimeMillis();
-        if (cachedAccessToken != null && now < tokenExpireTime) {
-            return cachedAccessToken;
+        if (cachedStableAccessToken != null && now < stableTokenExpireTime) {
+            return cachedStableAccessToken;
         }
 
         synchronized (this) {
-            if (cachedAccessToken != null && now < tokenExpireTime) {
-                return cachedAccessToken;
+            if (cachedStableAccessToken != null && now < stableTokenExpireTime) {
+                return cachedStableAccessToken;
             }
-            String token = doGetAccessToken();
-            // 微信access_token有效期7200秒,提前200秒过期缓存
-            cachedAccessToken = token;
-            tokenExpireTime = now + 7000 * 1000;
+            String token = doGetStableAccessToken();
+            cachedStableAccessToken = token;
+            stableTokenExpireTime = now + 7000 * 1000;
             return token;
         }
     }
 
+    private String doGetStableAccessToken() {
+        try {
+            String url = "https://api.weixin.qq.com/cgi-bin/stable_token";
+
+            JSONObject requestBody = new JSONObject();
+            requestBody.put("grant_type", "client_credential");
+            requestBody.put("appid", appid);
+            requestBody.put("secret", secret);
+
+            org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
+            headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
+            org.springframework.http.HttpEntity<String> entity = new org.springframework.http.HttpEntity<>(
+                    requestBody.toJSONString(), headers);
+
+            ResponseEntity<String> response = restTemplate.exchange(url,
+                    org.springframework.http.HttpMethod.POST, entity, String.class);
+            JSONObject json = JSON.parseObject(response.getBody());
+
+            if (json.containsKey("access_token")) {
+                return json.getString("access_token");
+            } else {
+                log.error("获取stable access_token失败: {}", json.toJSONString());
+                throw new RuntimeException("获取access_token失败");
+            }
+        } catch (Exception e) {
+            log.error("获取stable access_token异常", e);
+            throw new RuntimeException("获取access_token异常");
+        }
+    }
+
     private String doGetAccessToken() {
         try {
             String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",