前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WxJava | weixin-java-mp组件核心源码剖析+access_token管理的最佳实践

WxJava | weixin-java-mp组件核心源码剖析+access_token管理的最佳实践

作者头像
烟雨平生
发布2023-11-07 17:02:17
1.6K0
发布2023-11-07 17:02:17
举报
文章被收录于专栏:数字化之路数字化之路
  • 言:随着移动互联网的快速发展,微信公众号成为了企业与用户之间进行互动和沟通的重要渠道。为了更好地管理和维护微信公众号,本文将介绍如何基于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的稳定性工作已经搞定了。 微信公众号的多账户管理后面再展开

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-11-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 的数字化之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档