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

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

时间:2024-11-09 12:14:48浏览次数:6  
标签:accessToken 微信 token Access Token import

问题描述

在微信小程序或公众号的开发中,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";

    @Autowired
    public void setWxMaService(WxMaService wxMaService) {
        this.wxMaService = wxMaService;
    }

    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Autowired
    public 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 credential
                logger.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;
    }
}

标签:accessToken,微信,token,Access,Token,import
From: https://blog.csdn.net/qq_41520636/article/details/143643043

相关文章

  • DMA(Direct Memory Access,直接内存存取)是一种允许外设直接与计算机内存进行数据交换的
    DMA(直接内存存取)简介DMA(DirectMemoryAccess,直接内存存取)是一种允许外设直接与计算机内存进行数据交换的技术,绕过了CPU的参与。这种机制的优势在于,它能够显著提高数据传输效率,减轻CPU的负担,从而使得计算机能够处理更多的任务和更高的性能要求。在传统的输入输出(I/O)操作中,数据通......
  • Vue+SpringBoot的民宿预订系统 微信小程序
    关注博主迷路,收藏文章方便后续找到,以防迷路,最下面有联系博主项目介绍微信小程序的民宿预订系统设计的目的是为用户提供民宿客房、公告信息等方面的平台。与PC端应用程序相比,微信小程序的民宿预订系统的设计主要面向于民宿,旨在为管理员和用户、商家提供一个微信小程序的......
  • 基于微信小程序的微医问诊服务平台系统(源码+lw+部署文档+讲解等)
    课题摘要基于springboot+vue的小程序微医问诊服务平台系统是一款将医疗服务与互联网技术深度融合的创新应用,提供了源码、lw、部署文档及讲解。医生与患者管理系统对医生和患者信息进行全面管理。医生需通过严格的资质认证才能入驻平台,其个人资料包括姓名、职称、擅......
  • 基于微信小程序的民宿预订系统(源码+lw+部署文档+讲解等)
    课题摘要基于springboot+vue的小程序民宿预订系统是一款为游客和民宿经营者量身打造的便捷应用,同时配备源码、lw、部署文档和讲解。民宿信息展示系统详细展示丰富多样的民宿资源。每一家民宿都有精美的图片呈现,包括外观、房间内部装饰、周边环境(如美丽的海景、山景......
  • 微信小程序scroll-view详解及案例
    需求:实现类似美团外卖。1.点击左侧菜单右侧滚动到对应内容。2.滚动右侧内容左侧对应菜单高亮。一、首先介绍下scroll-view可滚动视图区域。案例用到如下属性(如需了解更多请访问官网https://developers.weixin.qq.com/miniprogram/dev/component/scroll-view.html):以下属性1.0.0版......
  • 微信小程序支付 php后台对接完整代码
    这个代码全是干货呀,拿过来可以直接使用。小程序在调起微信支付之前需要5个参数,这时候就需要携带code向后台请求,然后后台根据code获取openid再进行服务器之间的。。。。一、准备工作1、小程序注册,要以公司的以身份去注册一个小程序,才有微信支付权限;2、绑定商户号。3、在小程序......
  • 微信小程序获取某个元素或组件距离顶部的初始高度
    给元素加一个id然后使用wx.createSelectorQuery().select('#the-id').boundingClientRect(function(rect){rect.id//节点的IDrect.dataset//节点的datasetrect.left//节点的左边界坐标rect.right//节点的右边界坐标rect.top//节点的上边界坐标rect.bottom//节点的下......
  • 微信小程序获取时长页面
    //index/PageA.jsconstapp=getApp()vartimerPageA;//计时器varintPageATime=0Page({/***页面的初始数据*/data:{},//A页计时器countTime(){letthat=this//读取A页计时数值wx.getStorage({......
  • Python中实现微信支付
    目录一,准备环境1,要有微信公众号,商户平台账号2,支持的支付方式有3,备案域名一,扫码支付如图1所示,使用模式一生成支付二维码2,使用模式二生成支付二维码二,使用JSAPI发起微信支付  回到顶部一,准备环境#1,要有微信公众号,商户平台账号#https://pay.weixin.qq.......
  • 微信小程序的两种视频录制方式
    基础库1.3.0开始支持,低版本需做兼容处理。以Promise风格调用:支持需要页面权限:当前是插件页面时,宿主小程序不能调用该接口,反之亦然小程序插件:支持,需要小程序基础库版本不低于2.18.1微信Windows版:支持微信Mac版:支持功能描述打开另一个小程序参数Objectobject属性......