Magento支付网关开发:观察者如何重定向至支付网关URL?
Magento支付网关重定向与回调处理方案
一、解决重定向无效问题
sales_model_service_quote_submit_success事件触发时,Magento的响应流程已启动,直接用原生header()函数会被框架覆盖,需用Magento官方响应机制实现跳转:
1. 直接重定向(当前页面跳转)
通过注入ResponseFactory生成响应对象,设置跳转并终止后续流程:
观察者类代码
<?php namespace Vendor\Payment\Observer; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\App\ResponseFactory; class RedirectToGateway implements ObserverInterface { protected $_responseFactory; public function __construct( ResponseFactory $responseFactory ) { $this->_responseFactory = $responseFactory; } public function execute(Observer $observer) { // 你的Curl逻辑,获取支付网关跳转URL $paymentGatewayUrl = 'https://your-payment-gateway.com/redirect'; // 生成响应并设置跳转 $response = $this->_responseFactory->create(); $response->setRedirect($paymentGatewayUrl)->sendResponse(); // 必须终止后续流程,否则Magento会继续输出页面内容 exit; } }
2. 新标签页打开支付网关
服务器端无法直接控制浏览器新标签,需输出JS代码实现:
观察者类代码(需注入UrlInterface生成内部URL)
<?php namespace Vendor\Payment\Observer; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\App\ResponseFactory; use Magento\Framework\UrlInterface; class OpenGatewayInNewTab implements ObserverInterface { protected $_responseFactory; protected $_url; public function __construct( ResponseFactory $responseFactory, UrlInterface $url ) { $this->_responseFactory = $responseFactory; $this->_url = $url; } public function execute(Observer $observer) { $paymentGatewayUrl = 'https://your-payment-gateway.com/redirect'; // 生成订单成功页URL,可替换为其他页面 $successPageUrl = $this->_url->getUrl('checkout/onepage/success'); // 输出JS代码实现新标签打开+当前页跳回成功页 $html = <<<HTML <html> <body> <script> window.open("{$paymentGatewayUrl}", "_blank"); window.location.href = "{$successPageUrl}"; </script> </body> </html> HTML; $response = $this->_responseFactory->create(); $response->setContent($html)->sendResponse(); exit; } }
二、捕获支付成功响应(回调处理)
支付网关完成操作后,会通过**回调URL(Webhook)**通知你的站点,需创建自定义控制器处理:
1. 回调控制器代码
<?php namespace Vendor\Payment\Controller\Callback; use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context; use Magento\Sales\Model\OrderFactory; class Index extends Action { protected $_orderFactory; public function __construct( Context $context, OrderFactory $orderFactory ) { parent::__construct($context); $this->_orderFactory = $orderFactory; } public function execute() { $postData = $this->getRequest()->getPostValue(); // 1. 验证网关签名(核心!防止恶意请求) if (!$this->validateSignature($postData)) { $this->getResponse()->setHttpResponseCode(403)->setContent('Invalid signature'); return; } // 2. 根据网关返回的订单号加载订单 $orderIncrementId = $postData['order_id']; // 需和网关约定返回订单标识字段 $order = $this->_orderFactory->create()->loadByIncrementId($orderIncrementId); if (!$order->getId()) { $this->getResponse()->setHttpResponseCode(404)->setContent('Order not found'); return; } // 3. 根据网关返回状态更新订单 if ($postData['payment_status'] == 'success') { $order->setState(\Magento\Sales\Model\Order::STATE_PROCESSING) ->setStatus(\Magento\Sales\Model\Order::STATUS_PROCESSING) ->addStatusHistoryComment('支付成功:来自网关回调') ->save(); } else { $order->setState(\Magento\Sales\Model\Order::STATE_CANCELED) ->setStatus(\Magento\Sales\Model\Order::STATUS_CANCELED) ->addStatusHistoryComment('支付失败:来自网关回调') ->save(); } // 4. 返回响应给网关(一般返回200即可) $this->getResponse()->setHttpResponseCode(200)->setContent('OK'); } // 实现网关要求的签名验证逻辑,示例用HMAC-SHA256 private function validateSignature($postData) { $gatewaySecret = 'your-gateway-secret-key'; // 网关提供的密钥 $receivedSignature = $postData['signature']; // 网关返回的签名字段 unset($postData['signature']); // 移除签名字段后生成待签名字符串 $generatedSignature = hash_hmac('sha256', http_build_query($postData), $gatewaySecret); return hash_equals($generatedSignature, $receivedSignature); } }
2. 关键注意事项
- 回调URL需配置为公网可访问地址,否则网关无法推送通知
- 签名验证不可省略,必须严格按照网关文档实现,防止订单被恶意篡改
- 测试时可使用ngrok等工具将本地Magento站点暴露到公网,方便调试回调
内容的提问来源于stack exchange,提问作者Juniorfstack
相关产品推荐
相关产品推荐

