我使用的是redis作为存储服务器,来存储access_token,代码亲测没有任何问题

在做微信公众号模板推送的时候用到了access_token,但是有时推送成功,有时失败,报错显示为:

40001: invalid credential, access_token is invalid or not latest rid: 5fdb2087-1f36ab8e-5c34337a
因为AppSecret之前一直使用, 所以不会错误,所以只能是access_token失效。

百思不得其解,为啥有时候能成功,有时候失败呢?存储在redis中的access_token,绝对是在保质期内的,正确的值,再次查看官方文档,发现如下:

在这里插入图片描述
所以我此时考虑是有其他的用户通过公众号的appId重新生成过access_token,导致我这里的access_token失效。但是我登录到微信公众号后台发现生成access_token需要appId和secret,而secret生成过一次就隐藏了,别人不可能知道。

所以赶紧询问同时,有没有人和我同时在一个公众号内调用了access_token,果然有,随即赶紧更换成和我一样的存储方式,两者公用,失效问题解决

贴上redis存储access_token的代码(过期自动获最新的access_token)
class ClientException(Exception):
    pass
def check_error(json):
    """
    检测微信公众平台返回值中是否包含错误的返回码。
    如果返回码提示有错误,抛出一个 :class:`ClientException` 异常。否则返回 True 。
    """
    if "errcode" in json and json["errcode"] != 0:
        raise ClientException("{}: {}".format(json["errcode"], json["errmsg"]))
    return json


class Wechatopen(object):
    '''
    存储access_token
    '''
    # 定义redis的key
    key = 'access_token_hash'
    def __init__(self):
        self._token = None
        self.token_expires_at = None
        self.appid = settings.WECHAT_APP_ID
        self.appsecret = settings.WECHAT_APP_SECRET

    def request(self, method, url, **kwargs):
        if "params" not in kwargs:
            kwargs["params"] = {"access_token": self.token}
        if isinstance(kwargs.get("data", ""), dict):
            body = _json.dumps(kwargs["data"], ensure_ascii=False)
            body = body.encode('utf8')
            kwargs["data"] = body

        r = requests.request(
            method=method,
            url=url,
            **kwargs
        )
        r.raise_for_status()
        json = r.json()
        if check_error(json):
            return json

    def get(self, url, **kwargs):
        return self.request(
            method="get",
            url=url,
            **kwargs
        )

	# 调用此方法,获取到access_token
    def get_access_token(self):
        """
        判断现有的token是否过期。
        用户需要多进程或者多机部署可以手动重写这个函数
        来自定义token的存储,刷新策略。

        :return: 返回token
        """
        # 从redis中取出access_token和过期的额时间,并赋值给self._token和self.token_expires_at
        stream = redis.get(self.key)
        if stream:
            self._token,self.token_expires_at = loads(stream)
        if self._token:
            now = time.time()
            if self.token_expires_at - now > 60:
                return self._token
        # 如果过期的话,重新生成access_token,重置_token和token_expires_at
        json = self.grant_token()
        self._token = json["access_token"]
        self.token_expires_at = int(time.time()) + json["expires_in"]
        # 存入redis
        access_token_val = dumps([self._token,self.token_expires_at])
        redis.set(self.key,access_token_val)
        return self._token

    def grant_token(self):
        """
        获取 Access Token。
        每当调用这个包,便将数据存入reids,并且更新self._token和self.token_expires_at

        :return: 返回的 JSON 数据包
        """
        result = self.get(
            url="https://api.weixin.qq.com/cgi-bin/token",
            params={
                "grant_type": "client_credential",
                "appid": self.appid,
                "secret": self.appsecret
            }
        )
        return result

再次发现一个大问题:

微信模板推送,间接性的得到40001错误
access_token是用中控服务器存的,保证正确以及有效
发送微信模板信息时,同一时间发送,一部分成功,一部分失败

看到了微信社区也有人发现了同样的问题,但是官方目前没有解决结论,已关注这个问题
地址如下: https://developers.weixin.qq.com/community/develop/doc/000a0ca6f4c5f0f0fb996ced055c00

参考博客:https://blog.csdn.net/ZhangZuoMian/article/details/82902940

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐