diff --git a/backend/application/common/service/EasyWeChatService.php b/backend/application/common/service/EasyWeChatService.php index 82fa77d..136d0a0 100644 --- a/backend/application/common/service/EasyWeChatService.php +++ b/backend/application/common/service/EasyWeChatService.php @@ -31,6 +31,8 @@ class EasyWeChatService $this->app = new MiniAppApplication([ 'app_id' => $this->config['app_id'], 'secret' => $this->config['secret'], + // 稳定版凭证重复获取不会把上一张作废。旧接口并发刷新会返回 40001 + 'use_stable_access_token' => true, 'http' => ['throw' => false, 'timeout' => 10.0], ]); @@ -46,6 +48,24 @@ class EasyWeChatService ]); } + /** + * 刷新小程序 access_token。普通刷新不会使有效凭证失效;force 只在微信返回凭证无效时使用 + * @param bool $force + * @return string + */ + public function refreshMiniAccessToken($force = false) + { + $accessToken = $this->app->getAccessToken(); + if ($force && method_exists($accessToken, 'getStableAccessToken')) { + return $accessToken->getStableAccessToken(true); + } + if ($accessToken instanceof \EasyWeChat\Kernel\Contracts\RefreshableAccessToken) { + return $accessToken->refresh(); + } + + return ''; + } + /** * 小程序登录(code2session) * @param string $code wx.login 获取的 code diff --git a/backend/application/common/service/VirtualPayService.php b/backend/application/common/service/VirtualPayService.php index 38f35d7..d4fbc8c 100644 --- a/backend/application/common/service/VirtualPayService.php +++ b/backend/application/common/service/VirtualPayService.php @@ -384,6 +384,33 @@ class VirtualPayService if ($body === false) { throw new \Exception('虚拟支付参数编码失败'); } + $service = new EasyWeChatService(); + $result = self::requestXpay($service, $uri, $body, $sessionKey); + $errcode = (int)($result['errcode'] ?? 0); + // 40001 凭证不是最新,42001 凭证过期。刷新后只重试一次 + if ($errcode === 40001 || $errcode === 42001) { + Log::info('虚拟支付 access_token 失效,刷新后重试 ' . $uri); + $service->refreshMiniAccessToken(true); + $result = self::requestXpay($service, $uri, $body, $sessionKey); + } + Log::info('虚拟支付请求 ' . $uri . ' ' . json_encode([ + 'payload' => $payload, + 'res' => $result, + ], JSON_UNESCAPED_UNICODE)); + + return is_array($result) ? $result : []; + } + + /** + * @param EasyWeChatService $service + * @param string $uri + * @param string $body + * @param string $sessionKey + * @return array + * @throws \Exception + */ + private static function requestXpay(EasyWeChatService $service, $uri, $body, $sessionKey) + { // access_token 由小程序 HTTP 客户端自动附在 query 上,不参与 pay_sig $query = [ 'pay_sig' => hash_hmac('sha256', $uri . '&' . $body, self::appKey()), @@ -392,7 +419,6 @@ class VirtualPayService $query['signature'] = hash_hmac('sha256', $body, $sessionKey); } try { - $service = new EasyWeChatService(); $response = $service->app->getClient()->post($uri, [ 'query' => $query, 'headers' => ['Content-Type' => 'application/json'], @@ -403,10 +429,6 @@ class VirtualPayService Log::error('虚拟支付请求异常 ' . $uri . ' ' . $e->getMessage()); throw new \Exception('虚拟支付请求失败'); } - Log::info('虚拟支付请求 ' . $uri . ' ' . json_encode([ - 'payload' => $payload, - 'res' => $result, - ], JSON_UNESCAPED_UNICODE)); return is_array($result) ? $result : []; }