- 言:随着移动互联网的快速发展,微信公众号成为了企业与用户之间进行互动和沟通的重要渠道。为了更好地管理和维护微信公众号,本文将介绍如何基于WxJava SDK实现对access_token有效管理。 微信的"access_token"是有坑的,你知道有哪几个?
微信公众号管理平台要解决的问题
在微信公众号管理平台建设中,主要涉及两个场景: 1、调微信API执行相关操作 2、接收微信的回调并执行相关操作。
下载地址:https://www.processon.com/view/653e2a0a824d4a62d2d9c3e2
涉及到的三大系统: 微信客户端、微信后台服务、微信公众号管理系统【第三方服务】 唐成,公众号:的数字化之路微信生态圈 | 想让微信公众号做到“千人千面”?试试接入第三方服务!
weixin-java-mp组件简介
weixin-java-mp组件是一个基于Java语言开发的微信公众号开发工具包,是WxJava SDK在微信公众号场景的一个实现。
WxJava - 微信开发 Java SDK。 支持微信支付、微信开放平台、公众号、企业号/企业微信、小程序等的后端开发。 https://gitee.com/binary/weixin-java-tools
weixin-java-mp组件它提供了一系列的功能和方法,方便开发者快速集成和使用微信公众号的相关功能。
weixin-java-mp组件的架构主要包括以下几个部分:
1、配置管理:weixin-java-mp提供了配置管理的功能,方便开发者配置微信公众号的信息,如AppID、AppSecret等。开发者只需在代码中配置相应的信息即可使用weixin-java-mp进行开发。
2、API接口封装:weixin-java-mp将微信提供的API接口进行了封装,简化了开发者调用微信API的过程。开发者只需调用相应的方法即可完成对微信公众号的操作。
3、微信回调消息处理:weixin-java-mp提供了消息处理的功能,包括接收用户消息、处理事件推送等。开发者可以通过实现相应的消息处理器来对接收到的消息进行处理。
weixin-java-mp组件的核心类类图及作用域
高可用环境下管理access_token时遇到的问题
高可用(High Availability,HA)是指在系统发生故障或异常情况时,仍能够保持服务的稳定性和可用性,确保业务系统的持续运行。 什么是高可用五个9?系统的可用时间不能少于99.999%,即在一年中最多只有53分钟的故障时间。这是软件质量中用来衡量可用性的高标准。而相对的,"四个9"(99.99%)则被视为行业平均水平的可用性。 SparkDesk
要实现99.99%系统可用性,同一个服务的个数肯定>1。即使大于1个,也不能避免故障,譬如:语雀,这波故障,放眼整个互联网也是炸裂般的存在。
在高可用环境下,access_token的管理会遇到以下问题:
1、获取access_token的接口,每天调用次数限制。 2、access_token过期:access_token的有效期为2个小时,需要定期刷新; 3、access_token泄露:access_token是敏感信息,需要妥善保管,防止泄露。
解决办法如下:
1、定时刷新:设置定时任务,定期刷新access_token,确保其有效性;
2、使用缓存机制:将access_token缓存起来,减少频繁获取的次数; access_token需要进行缓存中心化管理。使用本地缓存会存在不一致的问题且强制刷新时比较困难。
高可用环境下access_token管理的最佳实践
技术方案:
要确保access_token是正常的,需要完成以下工作 :
1、确保缓存的aceess_token是正确的。 自定义一个WxMpService的实现,使用稳定版的获取access_token接口。
因为weixin-java-mp 4.5.0中仍然使用/cgi-bin/token来获取token。目前这个服务器是uat和pro环境共用。这两个环境互相隔离。如果uat环境的服务通过/cgi-bin/token获取到token,那么线上服务的token在5分钟后就会过期,但线上redis缓存的时间会大于5分钟。那么5分钟后,线上的使用这个token的操作就会报错“invalid access_token”,这就出现线上事故了。
另外,最近几个月中发现使用/cgi-bin/token时,微信没有保证在5分钟内新老access_token都可用。 所以强烈建议使用新接口: 稳定版接口https://api.weixin.qq.com/cgi-bin/stable_token 唐成,公众号:的数字化之路【微信生态圈】微信体系中的access_token有哪些?
2、使用中心化的中间件保存access_token。譬如 redis
本示例基于Redis中间件实现对access_token的中心化管理。
具体实现相关的类图:
step1:
step2:
具体实现:
代码语言:javascript复制 <dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.7.17</version>
</dependency>
代码语言:javascript复制// 在weixin-java-mp组件中WxMpService接口抽象了对微信API的调用。
// StableAccessTokenServiceImpl类使用了微信公众号的新token接口
@Slf4j
public class StableAccessTokenServiceImpl extends BaseWxMpServiceImpl<CloseableHttpClient, HttpHost> {
private CloseableHttpClient httpClient;
private HttpHost httpProxy;
...
@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
final WxMpConfigStorage config = this.getWxMpConfigStorage();
if (!config.isAccessTokenExpired() && !forceRefresh) {
return config.getAccessToken();
}
Lock lock = config.getAccessTokenLock();
boolean locked = false;
try {
do {
locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
if (!forceRefresh && !config.isAccessTokenExpired()) {
return config.getAccessToken();
}
} while (!locked);
try {
String json = String.format("{"grant_type": "client_credential", "appid": "%s", "secret": "%s"}", config.getAppId(), config.getSecret());
//
HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/cgi-bin/stable_token");
httpPost.setHeader("Content-Type", "application/json");
httpPost.setEntity(new StringEntity(json, "UTF-8"));
if (this.getRequestHttpProxy() != null) {
RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
httpPost.setConfig(requestConfig);
}
try (CloseableHttpResponse response = getRequestHttpClient().execute(httpPost)) {
String accessToken = this.extractAccessToken(new BasicResponseHandler().handleResponse(response));
log.info("获取accessToken完成 appid {} ", config.getAppId());
return accessToken;
} finally {
httpPost.releaseConnection();
}
} catch (IOException e) {
throw new WxRuntimeException(e);
}
} catch (InterruptedException e) {
throw new WxRuntimeException(e);
} finally {
if (locked) {
lock.unlock();
}
}
}
}
代码语言:javascript复制 @Bean
public WxMpService wxMpService() {
// 自定义调用微信API的 http请求组件
WxMpService wxMpService = new StableAccessTokenServiceImpl();
wxMpService.setMaxRetryTimes(3);
return wxMpService;
}
代码语言:javascript复制 @Bean
public RedisTemplateWxRedisOps redisTemplateWxRedisOps(StringRedisTemplate stringRedisTemplate) {
//使用Redis来存取token
return new RedisTemplateWxRedisOps(stringRedisTemplate);
}
至此,access_token的稳定性工作已经搞定了。 微信公众号的多账户管理后面再展开