| | |
| | | } |
| | | |
| | | public String exchangePhoneNumber(String code) { |
| | | String token = clientAccessToken(); |
| | | String token = clientAccessToken(false); |
| | | Map<String, Object> response = post("/wxa/business/getuserphonenumber?access_token=" + encode(token), Map.of("code", code.trim())); |
| | | // 微信返回 40001 时,缓存的 access_token 可能已被其它实例刷新。使用稳定 |
| | | // 令牌接口强制刷新一次并重试,避免把令牌问题误报成手机号授权失效。 |
| | | if (number(response.get("errcode"), 0) == 40001) { |
| | | token = clientAccessToken(true); |
| | | response = post("/wxa/business/getuserphonenumber?access_token=" + encode(token), Map.of("code", code.trim())); |
| | | } |
| | | ensureSuccess(response, "手机号授权已失效,请重新授权"); |
| | | Object phoneInfo = response.get("phone_info"); |
| | | if (!(phoneInfo instanceof Map<?, ?> raw)) throw new BusinessException(ErrorCode.CONFLICT, "未获取到微信手机号,请重新授权"); |
| | |
| | | return phone; |
| | | } |
| | | |
| | | private String clientAccessToken() { |
| | | private String clientAccessToken(boolean forceRefresh) { |
| | | long now = System.currentTimeMillis(); |
| | | if (!accessToken.isBlank() && now < accessTokenExpiresAt) return accessToken; |
| | | if (!forceRefresh && !accessToken.isBlank() && now < accessTokenExpiresAt) return accessToken; |
| | | synchronized (this) { |
| | | now = System.currentTimeMillis(); |
| | | if (!accessToken.isBlank() && now < accessTokenExpiresAt) return accessToken; |
| | | Map<String, Object> response = get("/cgi-bin/token", Map.of( |
| | | "grant_type", "client_credential", |
| | | if (!forceRefresh && !accessToken.isBlank() && now < accessTokenExpiresAt) return accessToken; |
| | | Map<String, Object> response = post("/cgi-bin/stable_token", Map.of( |
| | | "appid", required(properties.getAppId()), |
| | | "secret", required(properties.getAppSecret()))); |
| | | "secret", required(properties.getAppSecret()), |
| | | "grant_type", "client_credential", |
| | | "force_refresh", forceRefresh)); |
| | | // 兼容旧微信接口/网关:稳定令牌接口不可用时再回退到旧接口。 |
| | | if (number(response.get("errcode"), 0) != 0 && !forceRefresh) { |
| | | response = get("/cgi-bin/token", Map.of( |
| | | "grant_type", "client_credential", |
| | | "appid", required(properties.getAppId()), |
| | | "secret", required(properties.getAppSecret()))); |
| | | } |
| | | ensureSuccess(response, "微信服务暂不可用,请稍后重试"); |
| | | String token = text(response.get("access_token")); |
| | | long expiresIn = number(response.get("expires_in"), 7200); |