当前位置: 首页 > news >正文

如何在微服务架构中优化微信 Access Token 管理:解决频率限制与过期问题的最佳实践

问题描述

在微信小程序或公众号的开发中,Access Token 是调用微信接口的关键凭证。然而,由于微信对 Access Token 的访问频率和刷新操作有严格的限制(每个 Access Token 有效期为 2 小时,刷新频率为 2000 次/天),微服务架构中多个服务或实例可能会频繁请求 Access Token,导致访问频率超限,或出现 token 已过期的问题。如何在微服务架构中高效、可靠地管理和共享 Access Token,成为开发过程中的一大挑战。

技术要点

  1. 集中化的 Access Token 管理

    • 使用单独的服务或中间件来管理 Access Token 的获取、刷新和分发,将其独立为一个微服务或缓存服务,避免各个业务服务直接请求微信接口。
  2. 缓存策略

    • 在集中化管理的基础上,使用 Redis 等高可用缓存来存储 Access Token。这样可以让不同的微服务实例通过缓存读取共享的 Access Token,减少频繁刷新带来的访问次数限制问题。
  3. Token 刷新机制

    • 实现自动刷新策略,在 Access Token 过期前通过定时任务或延迟刷新机制来更新 Access Token,确保各服务始终使用最新的有效凭证。
    • 可以使用 Redis 的 TTL 机制或者基于时间戳的方式,提前检测和判断 Access Token 是否接近过期。
  4. 锁机制防止并发刷新

    • 防止多个实例在 Access Token 接近过期时同时刷新,造成重复请求,可以采用 Redis 分布式锁机制确保在某一时刻只有一个实例负责刷新 Access Token,并将最新的 token 存储到缓存中。
  5. 容错和降级处理

    • Access Token 刷新失败的情况下,为调用方返回一个预定义的错误或重试机制,避免因凭证不可用导致的整体系统不可用。
    • 增加熔断或限流策略,防止在异常情况下对微信接口产生过多请求。
  6. 日志和监控

    • 针对 Access Token 的获取、刷新和过期情况,加入日志和监控,便于追踪和及时发现异常,提升系统的稳定性和可维护性。

解决代码

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import me.chanjar.weixin.common.error.WxErrorException;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/*** 微信小程序访问令牌单例*/
@Component
public class AccessTokenMaSingleton {private static final Logger logger = LoggerFactory.getLogger(AccessTokenMaSingleton.class);private WxMaService wxMaService;private StringRedisTemplate redisTemplate;private RedissonClient redissonClient;private static final String ACCESS_TOKEN_KEY = "wechat:access_token";private static final String LOCK_KEY = "wechat:access_token_lock";@Autowiredpublic void setWxMaService(WxMaService wxMaService) {this.wxMaService = wxMaService;}@Autowiredpublic void setRedisTemplate(StringRedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}@Autowiredpublic void setRedissonClient(RedissonClient redissonClient) {this.redissonClient = redissonClient;}public String getAccessToken() throws Exception {ValueOperations<String, String> ops = redisTemplate.opsForValue();String accessToken = ops.get(ACCESS_TOKEN_KEY);if (StrUtil.isEmpty(accessToken)) {RLock lock = redissonClient.getLock(LOCK_KEY);try {lock.lock();accessToken = ops.get(ACCESS_TOKEN_KEY);if (StrUtil.isEmpty(accessToken)) {accessToken = wxMaService.getAccessToken(true);ops.set(ACCESS_TOKEN_KEY, accessToken, 110, TimeUnit.MINUTES); // 微信访问令牌的有效期为110分钟}} finally {lock.unlock();}}return accessToken;}public String callWeChatApi(String repostUrl, JSONObject param) {try {String accessToken = this.getAccessToken(); // 使用单例模式获取 access_token// 使用 accessToken 调用微信接口// 示例:调用某个微信接口String url = repostUrl + "?access_token=" + accessToken;// 发起请求return HttpUtil.post(url, param.toJSONString());} catch (WxErrorException e) {if (e.getError().getErrorCode() == 40001) { // invalid credentiallogger.warn("Access token is invalid, refreshing and retrying...");try {String newAccessToken = this.getAccessToken(); // 自动刷新 access_token// 重新发起请求// 示例:重新调用某个微信接口String url = repostUrl + "?access_token=" + newAccessToken;// 发起请求return HttpUtil.post(url, param.toJSONString());} catch (Exception ex) {logger.error("Failed to refresh access token", ex);}} else {logger.error("Error calling WeChat API", e);}} catch (Exception e) {logger.error("Error calling WeChat API", e);}return null;}
}

http://www.mrgr.cn/news/69073.html

相关文章:

  • Word_小问题解决_1
  • 【日常记录-Git】git log
  • C#自定义特性-SQL
  • MySQL —— MySQL逻辑架构与查询过程
  • WPF-控件的属性值的类型转化
  • 供应SW6301V单C口多协议升降压移动电源IC
  • SpringBoot2~~~
  • WOA-RF|鲸鱼算法-随机森林-回归-降维|多变量特征筛选降维-回归预测|Matlab
  • JAVA开源项目 服装销售平台 计算机毕业设计
  • 嵌入式linux中gpio子系统的开发与实现
  • 2024年最新互联网大厂精选 Java 面试真题集锦(JVM、多线程、MQ、MyBatis、MySQL、Redis、微服务、分布式、ES、设计模式)
  • 丹摩征文活动 |【AI落地应用实战】文本生成语音Parler-TTS + DAMODEL复现指南
  • 什么是上拉和下拉
  • 弄巧成拙的 PFC(Priority-based Flow Control)
  • SpringBoot框架:共享汽车行业的技术升级
  • 腾讯云双十一程序员的「采购单拼团攻略」
  • 进程相关内容
  • (done) gdb 在系统编程中的调试技巧
  • Redis中的数据结构
  • 四期书生大模型实战营(【基础岛】- 第1关 | 书生·浦语大模型开源开放体系)
  • 探针台的维护方法
  • Programming language theory 编程语言理论-03-惰性求值 Lazy Evaluation
  • 代码随想录算法训练营Day13 | 二叉树理论基础、递归遍历、迭代遍历、统一迭代、层序遍历
  • Kafka经典面试题
  • 前端必知必会-JavaScript 数组属性和方法
  • JDBC学习记录