import time import asyncio import httpx from app.config import settings # token 缓存 _token_cache: dict = {} _lock = asyncio.Lock() async def get_access_token() -> str: """获取 access_token,带缓存和并发刷新保护""" now = int(time.time()) if _token_cache.get("access_token") and _token_cache.get("expires_at", 0) > now + 300: return _token_cache["access_token"] async with _lock: # 双重检查 if _token_cache.get("access_token") and _token_cache.get("expires_at", 0) > now + 300: return _token_cache["access_token"] async with httpx.AsyncClient() as client: url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken" resp = await client.get(url, params={ "corpid": settings.corpid, "corpsecret": settings.secret, }) data = resp.json() if data.get("errcode") != 0: raise Exception(f"获取 access_token 失败: {data}") _token_cache["access_token"] = data["access_token"] _token_cache["expires_at"] = now + data["expires_in"] return _token_cache["access_token"]