Shopware 6.6自定义支付插件出现CHECKOUT__PAYMENT_TOKEN_INVALIDATED错误
自定义Shopware支付插件对接问题求助
问题概述
- Shopware生成的return url超出支付提供商255字符限制,已通过创建伪return url并将真实URL存入数据库解决,想确认该方案是否最优
- 支付交易成功时流程正常
- 支付交易失败后,重试同一支付方式会触发
CHECKOUT__PAYMENT_TOKEN_INVALIDATED异常
相关代码
Pay方法代码
public function pay(AsyncPaymentTransactionStruct $transaction, RequestDataBag $dataBag, SalesChannelContext $salesChannelContext): RedirectResponse { $context = $salesChannelContext->getContext(); $buy_order = $transaction->getOrder()->getOrderNumber(); $session_id = $_COOKIE["session-"]; $amount = $transaction->getOrderTransaction()->getAmount()->getTotalPrice(); $return_url = $transaction->getReturnUrl(); // Too long, max 256 $return_url_fake = "http://" . $_SERVER['SERVER_NAME'] . "/gentawebpay/finish?order=" . $buy_order; $redirectUrl = $this->sendReturnUrlToExternalGateway($return_url_fake, $buy_order, $session_id, $amount); $this->gentaPaymentTransactionRepository->create([ [ 'order_number' => $buy_order, 'transaction_token' => $redirectUrl->getToken(), 'sw_return_url' => $return_url, ] ], $context); // Redirect to external gateway return new RedirectResponse( $redirectUrl->getUrl().'?token_ws='.$redirectUrl->getToken() ); }
Finalize方法代码
public function finalize(AsyncPaymentTransactionStruct $transaction, Request $request, SalesChannelContext $salesChannelContext): void { $token_ws = $request->get('token_ws') ?? null; $transactionId = $transaction->getOrderTransaction()->getId(); if (!$token_ws) { die ('not a normal flow.'); } $response = (new Transaction)->commit($token_ws); $context = $salesChannelContext->getContext(); if ($response->isApproved()) { $this->transactionStateHandler->paid($transaction->getOrderTransaction()->getId(), $context); } else { $this->transactionStateHandler->fail($transaction->getOrderTransaction()->getId(), $context); throw PaymentException::asyncFinalizeInterrupted( $transaction->getOrderTransaction()->getId(), 'An error occurred during the communication with external payment gateway' ); } }
发送return url至外部网关方法代码
private function sendReturnUrlToExternalGateway(string $getReturnUrl, string $buy_order, string $session_id, float $amount): object { $paymentProviderUrl = ''; // Do some API Call to your payment provider $transaction = new Transaction(); $response = $transaction->create($buy_order, $session_id, $amount, $getReturnUrl); $paymentProviderUrl = $response; return $paymentProviderUrl; }
错误截图

解决方案建议
1. 伪Return URL方案评估
你的方案是可行的,但可以优化细节:
- 避免直接使用
$_COOKIE["session-"],改用Shopware内置会话管理方法$salesChannelContext->getSession()->getId(),更安全合规 - 伪URL建议使用HTTPS协议,避免明文传输订单号
- 数据库存储时,建议关联
order_transaction_id而非仅order_number,一个订单可能存在多笔交易,避免数据冲突 - 给伪URL添加签名验证(比如用订单号+密钥生成哈希),防止恶意请求
2. CHECKOUT__PAYMENT_TOKEN_INVALIDATED异常解决
该异常由Shopware抛出,核心原因是重试支付时引用了已失效的旧支付令牌,解决思路:
- 创建新交易重试:支付失败后,不要复用原订单交易,调用Shopware订单交易API生成新的交易记录,再发起支付请求
- 清理旧令牌关联:在
finalize方法标记交易失败后,清理数据库中关联的旧支付令牌,避免重试时引用 - 确认提供商侧状态:支付失败后,支付提供商通常会作废对应交易的token,重试必须生成新的交易token,不能复用之前的
token_ws - 调整重试逻辑:在前端或插件中,用户触发重试时,重新调用
pay方法生成新的交易和令牌,而非复用原有流程
内容的提问来源于stack exchange,提问作者Daniel Soublett
相关产品推荐
相关产品推荐

