You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 15:35:33