最近在做微信的發送模版消息,在測試的時候發現有的時候能夠發送,有時候無法發送,查了相關的日志(日志記錄發送結果很重要!!),看到了微信返回的錯誤消息,發現是 invalid credential, access_token is invalid or not latest hint: [QM1DJA0040vr22],原來是assess_token過期了。
我想了問題可能出現在下面幾點:
測試服和線上服使用同一個app_id和secret來獲取,可能會存在其中一方獲取的token是舊的;
代碼中沒有統一的從一個地方來獲取,而是直接從官網獲取,導致不統一(看了代碼,沒有發現單獨獲取token的地方);
請求獲取新的token的時候失敗(應該不可能,因為請求成功以后會在redis中緩存兩個小時,但是發現沒過多久又再次失效,因此主要原因應該不是這個);
異步隊列等待的時間較長,正好執行的時候token已經更新(應該不可能,獲取token是在異步函數中執行,而不是通過函數參數來傳遞);
但是實在想不出問題確切的原因,也只能先在其基礎上進行fix了。
我的做法:是在內層函數中,如果執行失敗,並且是access_token過期的異常,則會在request的時候拋出專門的異常。在外圍函數如果接收到了這個異常,則會拋出讓裝飾器接收到,裝飾器收到這個異常后會刪掉緩存中的token,並且重新執行該函數,這樣該函數在執行的時候,就會去主動的獲取最新的token。我大致寫了下代碼,如下:
# -*- coding: utf-8 -*-
from functools import wraps
from django.utils.decorators import available_attrs
import logging
class WeiXinTokenExpiredException(Exception):
pass
def _delete_weixin_expired_access_token():
"""
刪除微信過期的token
"""
pass
def _send_weixin_mini_template_msg(msg):
"""
發送微信模版信息
:param msg:
:return:
"""
return {}
def weixin_token_expired_decorator(func):
"""
捕獲微信asess_token過期的裝飾器
如果拋出WeiXinTokenExpiredException,則刪除緩存中的token
並且重新執行
:param func: 執行函數
"""
def decorator(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(*args, **kwargs):
try:
return view_func(*args, **kwargs)
except WeiXinTokenExpiredException:
_delete_weixin_expired_access_token()
return view_func(*args, **kwargs)
return _wrapped_view
if func is None:
return decorator
return decorator(func)
@weixin_token_expired_decorator
def push_weixin_mini_template_msg(msg):
"""
發送模版消息
:param msg:
:return:
"""
result = {}
try:
result = _send_weixin_mini_template_msg(msg)
logging.info("_send_weixin_mini_result %s", result)
except:
if 'error_code' in result and result['error_code'] == 42001:
raise WeiXinTokenExpiredException
return result
吐槽一下,微信獲取token的場景很多,別弄混了~
