如何在 Opencart 中配置 Postback 和 Return URL?
结论
假设代码位于:
catalog/controller/payment/dragonpay.php
控制器类是 ControllerPaymentDragonpay,那么 callback() 对应的 OpenCart 路由通常为:
https://你的域名/index.php?route=payment/dragonpay/callback
可以先向 Dragonpay 提供以下地址:
Postback URL:
https://你的域名/index.php?route=payment/dragonpay/callback
Return URL:
https://你的域名/index.php?route=payment/dragonpay/callback
当前的 callback() 会验证签名、更新订单状态,然后将浏览器重定向到:
https://你的域名/index.php?route=checkout/success
更稳妥的设计是为 Postback 和 Return 分别设置入口。Postback 负责在服务器端更新订单,Return 负责将顾客带回商店。不要直接把 checkout/success 设置为 Postback URL,因为这个路由不会验证 Dragonpay 通知,也不会更新订单状态。
URL 如何确定
OpenCart 控制器 URL 通常采用以下格式:
index.php?route=控制器路径/方法名
例如,文件:
catalog/controller/payment/dragonpay.php
中的方法:
public function callback()
对应的路由是:
index.php?route=payment/dragonpay/callback
在前面加上商店的 HTTPS 域名,就得到完整 URL:
https://shop.example.com/index.php?route=payment/dragonpay/callback
如果 OpenCart 安装在 /store/ 等子目录中,URL 应写成:
https://shop.example.com/store/index.php?route=payment/dragonpay/callback
不要根据浏览器中显示的 SEO URL 推测通知地址。支付网关回调一般应使用完整、稳定的原始路由 URL。
OpenCart 版本或扩展目录结构不同,路由也可能不同。例如,控制器位于:
catalog/controller/extension/payment/dragonpay.php
对应路由通常是:
index.php?route=extension/payment/dragonpay/callback
最终地址应以实际的控制器文件路径和类结构为准。
分开设置 Postback 和 Return
Postback 是 Dragonpay 服务器主动请求商店服务器的地址。即使顾客关闭支付页面,Postback 也应能独立完成订单状态更新。
Return URL 则是顾客支付完成后,浏览器返回商店的地址,主要用于显示支付结果,不能作为确认付款的唯一依据。
可以设置为:
Postback URL:
https://shop.example.com/index.php?route=payment/dragonpay/callback
Return URL:
https://shop.example.com/index.php?route=payment/dragonpay/return
控制器可以按下面的方式拆分:
public function callback() {
$data = $this->request->post;
// 如果 Dragonpay 明确使用 GET 通知,可改为:
// $data = $this->request->get;
$order_id = isset($data['txnid']) ? (int)$data['txnid'] : 0;
$ref_no = isset($data['refno']) ? $data['refno'] : '';
$status = isset($data['status']) ? $data['status'] : '';
$message = isset($data['message']) ? $data['message'] : '';
$digest = isset($data['digest']) ? $data['digest'] : '';
$this->load->model('checkout/order');
$password = $this->config->get('dragonpay_pwd');
$digest_string = $order_id . ':' . $ref_no . ':' .
$status . ':' . $message . ':' . $password;
$expected_digest = sha1($digest_string);
$order_info = $this->model_checkout_order->getOrder($order_id);
if (!$order_info || !hash_equals($expected_digest, $digest)) {
$this->response->addHeader(
$this->request->server['SERVER_PROTOCOL'] . ' 400 Bad Request'
);
$this->response->setOutput('INVALID');
return;
}
switch (strtoupper($message)) {
case 'SUCCESS':
$order_status_id =
$this->config->get('dragonpay_completed_status_id');
break;
case 'FAILURE':
$order_status_id =
$this->config->get('dragonpay_failed_status_id');
break;
case 'PENDING':
$order_status_id =
$this->config->get('dragonpay_pending_status_id');
break;
default:
$order_status_id =
$this->config->get('config_order_status_id');
break;
}
if (!$order_info['order_status_id']) {
$this->model_checkout_order->confirm(
$order_id,
$order_status_id
);
} else {
$this->model_checkout_order->update(
$order_id,
$order_status_id
);
}
$this->response->setOutput('OK');
}
public function return() {
$this->redirect(
$this->url->link('checkout/success', '', 'SSL')
);
}
究竟使用 GET 还是 POST,成功后应返回什么内容,以及签名字段采用什么拼接顺序,都要以当前接入的 Dragonpay API 文档为准。上面的代码仅用于说明 OpenCart 端如何拆分职责。
暂时不拆分方法时
现有 callback() 同时处理两项工作:
- 验证 Dragonpay 参数并更新订单。
- 将顾客重定向到
checkout/success。
如果 Dragonpay 允许 Postback URL 和 Return URL 使用同一地址,可以暂时把两者都设置为:
https://shop.example.com/index.php?route=payment/dragonpay/callback
这种配置可以工作,但不够理想。服务器发起的 Postback 不需要跳转到成功页面,浏览器也可能重复发送 Return 请求。因此,订单更新逻辑必须具备幂等性,避免重复确认同一笔交易。
当前代码需要注意的问题
SUCESS 很可能是拼写错误
代码中写的是:
case 'SUCESS':
通常应该写成:
case 'SUCCESS':
不过,Dragonpay 实际返回的是 status 代码还是 message 文本,仍需查阅接口文档,不能仅凭字段名称判断。如果返回值并非 SUCCESS、FAILURE 或 PENDING,当前的 switch 将无法匹配。
当前代码只读取 GET 参数
代码通过下面的方式读取参数:
$this->request->get['txnid']
如果 Dragonpay 使用 HTTP POST 发送 Postback,这段代码就读不到相关参数。此时应按照文档改用:
$this->request->post
如果确实需要同时兼容两种请求方式,可以明确合并允许接收的字段,但不要直接、无条件地信任 $_REQUEST。
Return URL 不能决定付款是否成功
顾客可以直接访问 Return URL,也可能在付款后没有返回商店。订单是否支付成功,应以通过签名验证的服务器 Postback 为准,不能根据顾客是否访问 checkout/success 来判断。
回调地址必须能从公网访问
Postback URL 应满足以下条件:
- 使用有效的 HTTPS 证书;
- 无需登录即可访问;
- 不受维护模式、Basic Auth 或防火墙规则阻挡;
- 不依赖顾客的 Session;
- 不输出 PHP 报错、调试信息或 HTML 页面;
- 能处理 Dragonpay 重复发送的通知。
配置完成后,应使用 Dragonpay 提供的测试环境或通知测试功能,逐项验证请求方式、字段名称、签名、HTTP 状态码、响应正文和订单状态是否符合接口要求。
备注:内容仅供参考。
