[#ArtifactTitle:斗拱考试实战:支付宝正扫+退款场景完整实现与踩坑记录]

---
title: 斗拱考试实战:支付宝正扫+退款场景完整实现与踩坑记录
date: 2026-01-07
author: 夏末浅笑
tags: [汇付支付, 斗拱考试, PHP, 支付宝, 退款]
categories: [技术实战]
---

# 斗拱考试实战:支付宝正扫+退款场景完整实现与踩坑记录

**作者**:夏末浅笑  
**博客**:[https://blog.ccswust.org/](https://blog.ccswust.org/)  
**创建日期**:2026-01-07

## 前言

最近需要完成斗拱考试的支付宝正扫+退款场景,整个过程中遇到了不少坑,特此记录下来,希望能帮助到后来者。本文将详细介绍如何使用汇付支付的PHP SDK实现PC端支付宝扫码支付和交易退款功能,并深入分析常见问题的解决方案。

## 一、项目背景

### 考试要求

- **聚合正扫**:调用聚合正扫API,`trade_type = A_NATIVE`
- **支付金额**:向个人账户内支付≤¥1.00金额
- **交易退款**:调用交易退款API,将支付款退还给用户
- **流水号格式**:`req_seq_id`必须包含用户ID和请求日期,格式为:`用户ID_日期_随机数`

### 技术栈

- **后端**:PHP 7.4 + 汇付支付SDK V2.0.23
- **前端**:原生JavaScript + 官方PC端SDK
- **部署环境**:Nginx + HTTPS

## 二、项目结构

huifu_exam_complete/
├── api/ # 后端API接口
│ ├── pc_pay.php # PC端支付宝扫码支付接口
│ ├── pc_refund.php # 交易退款接口
│ ├── query.php # 交易查询接口
│ ├── notify.php # 异步通知处理
│ └── loader.php # SDK加载器
├── public/ # 前端页面
│ └── pc/ # PC端收银台
│ ├── cashier.html # 收银台页面
│ ├── refund.html # 退款测试页面
│ ├── pay.js # 支付逻辑
│ └── config/ # 配置文件
└── sdk/ # 汇付支付SDK
└── BsPaySdk/ # PHP SDK核心文件


## 三、核心实现

### 3.1 支付接口实现

支付接口使用聚合正扫API,交易类型为A_NATIVE(支付宝扫码)。

```php
post("v3.trade.payment.jspay", $paramsInfo, '', 'default');

// 4. 处理响应
if (!$result || $result->isError()) {
    // 失败处理
} else {
    // 成功处理,返回二维码
}
?>

关键点

  • 流水号格式必须包含用户ID和日期
  • 交易类型必须为A_NATIVE
  • 支付金额必须≥0.10元(手续费限制)

3.2 退款接口实现

退款接口使用V2版本的交易退款API。

post("v2.trade.payment.scanpay.refund", $paramsInfo, '', 'default');

    // 5. 处理响应
    if (!$result || $result->isError()) {
        // 失败处理
    } else {
        // 成功处理
    }
} catch (Exception $e) {
    // 异常处理
}
?>

关键点

  • 必须使用V2版本退款接口(v2.trade.payment.scanpay.refund
  • 必须使用汇付全局流水号(hf_seq_id)作为原交易标识
  • namespace声明必须在文件第一行

四、踩坑记录

坑1:SDK类加载失败

错误信息Fatal error: Class 'BsPaySdk\request\BaseRequest' not found

原因:直接加载请求类文件,但没有加载SDK的init.php文件,导致父类BaseRequest没有被正确加载。

解决方案:使用loader.php统一加载SDK,确保类加载顺序正确。

// loader.php
require_once dirname(__FILE__). "/../sdk/BsPaySdk/init.php";
use BsPaySdk\core\BsPay;
BsPay::init(dirname(__FILE__).'/../sdk/Composer/BsPayConfig.json', false);

坑2:商户私钥截断

错误信息api error

原因:商户私钥在配置文件中只显示到"...",导致签名验证失败。

解决方案:确保BsPayConfig.json中的商户私钥完整,不要截断。

坑3:namespace声明位置错误

错误信息Fatal error: Namespace declaration statement has to be the very first statement

原因:namespace声明之前有其他代码或空行。

解决方案:namespace声明必须在文件第一行,前面不能有任何代码或空行。

<?php
namespace BsPayDemo; // 必须在第一行
use BsPaySdk\core\BsPay;
// 其他代码...

坑4:退款接口版本错误

错误信息原交易未入账

原因:使用了V3版本的退款接口,但应该使用V2版本。

解决方案:使用官方示例代码中的V2接口:v2.trade.payment.scanpay.refund

坑5:支付金额不足

错误信息交易金额不足以支付手续费

原因:支付金额为0.01元,不足以支付手续费。

解决方案:支付金额必须≥0.10元,建议使用0.50元。

坑6:前端收到HTML而非JSON

错误信息Unexpected token '<', "<!doctype html>..."

原因:PHP文件未正确执行,返回了HTML错误页面。

解决方案

  • 检查文件路径是否正确
  • 检查PHP环境是否正常
  • 检查文件权限是否正确
  • 增强前端错误处理,显示实际响应内容

坑7:退款参数错误

错误信息原交易不存在

原因:退款时使用了错误的交易标识。

解决方案:退款必须使用汇付全局流水号(hf_seq_id),而不是商户流水号(req_seq_id)。

坑8:Content-Type拼写错误

错误信息Unexpected token '<'

原因:前端http.js中Content-Type拼写错误:uft-8utf-8

解决方案:修正拼写错误:Content-Type: application/json; charset=utf-8

五、部署步骤

1. 环境准备

  • PHP 7.4+
  • Nginx/Apache
  • SSL证书(HTTPS)

2. 文件部署

# 上传文件到网站根目录
cd /www/wwwroot/yourdomain.com
unzip huifu_exam_complete.zip
cd huifu_exam_complete

# 设置目录权限
chmod -R 755 .
chmod -R 777 logs

3. 配置商户信息

修改 sdk/Composer/BsPayConfig.json

{
    "sys_id": "6666000108840829",
    "product_id": "YYZY",
    "rsa_merch_private_key": "完整的商户私钥",
    "rsa_huifu_public_key": "完整的汇付公钥",
    "huifu_id": "6666000109133323"
}

4. 配置Nginx

server {
    listen 443 ssl;
    server_name yourdomain.com;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    root /www/wwwroot/yourdomain.com/huifu_exam_complete;
    index index.html;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

5. 测试

访问:https://yourdomain.com/huifu_exam_complete/public/pc/cashier.html?price=0.5

六、验证结果

支付成功

{
    "resp_code": "000000",
    "resp_desc": "下单成功",
    "json_data": {
        "resp_code": "00000100",
        "resp_desc": "下单成功",
        "hf_seq_id": "002900TOP1A260107164650P355ac139d1100000",
        "req_seq_id": "1337734717469949952_20260107_888494"
    },
    "pay_info": "https://qr.alipay.com/xxxxx"
}

退款成功

{
    "resp_code": "000000",
    "resp_desc": "退款成功",
    "json_data": {
        "resp_code": "00000000",
        "resp_desc": "交易成功",
        "hf_seq_id": "003100TOP1B260107185639P550ac139d6f00000",
        "req_seq_id": "1337734717469949952_20260107_888494",
        "trans_amt": "0.50"
    }
}

七、考试提交流水号

根据日志分析,以下流水号已成功通过验证:

退款请求流水号1337734717469949952_20260107_888494

此流水号符合考试要求:

  • ✅ 包含用户ID(1337734717469949952)
  • ✅ 包含请求日期(20260107)
  • ✅ 格式正确(用户ID_日期_随机数)
  • ✅ 退款交易成功(resp_code: 00000000)

八、注意事项

  • 支付金额:不能低于0.10元(手续费限制)
  • 退款标识:必须使用汇付全局流水号(hf_seq_id
  • 流水号格式:必须包含用户ID和日期
  • HTTPS:必须使用HTTPS协议
  • 服务器时间:确保服务器时间准确
  • 完整密钥:商户私钥必须完整,不能截断
  • namespace位置:必须在文件第一行

九、参考文档

十、总结

通过这次斗拱考试,我深入理解了汇付支付的API调用流程和常见问题。关键要点:

  1. 严格按照官方示例代码:不要随意修改官方示例代码的结构
  2. 注意细节:namespace位置、密钥完整性、接口版本等细节很重要
  3. 充分测试:每个环节都要充分测试,确保功能正常
  4. 日志记录:详细的日志记录有助于问题排查

希望这篇博客能帮助到正在进行斗拱考试的开发者。如果有任何问题,欢迎在我的博客留言交流。

项目地址huifu_exam_complete
作者博客https://blog.ccswust.org/
创建日期:2026-01-07