# Alipay Face To Face

> 实现、审查、迁移或排查支付宝当面付扫码支付，包括 alipay.trade.precreate 预创建二维码、RSA2 请求签名、异步通知验签、主动查询、支付状态轮询、订单与金额校验、幂等发放权益，以及 Cloudflare Workers 部署。用户提到“支付宝当面付”“扫码支付”“无法生成二维码”“验签出错”“支付成功未到账”“alipay.trade.precreate”“支付宝 notify/callback”时使用。

- Skill: `xianyu110/alipay-face-to-face` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add xianyu110/alipay-face-to-face`
- Raw SKILL.md: https://api.skillmd.com/api/skills/xianyu110/alipay-face-to-face/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: xianyu110 (https://skillmd.com/u/xianyu110)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/xianyu110/alipay-face-to-face

---


# 支付宝当面付

## 安全边界

- 禁止输出、记录或提交真实 App ID、应用私钥、应用公钥、支付宝公钥、商户 ID、证书、`.env`、回调原文或完整订单数据。
- 要求用户通过服务端环境变量或部署平台 Secret 提供凭据，不要让用户在对话中粘贴密钥。
- 只在诊断中输出参数名、错误码、支付状态和脱敏标识；标识最多保留前 4 位与后 4 位。
- 禁止通过关闭请求签名、通知验签、金额校验或幂等检查来绕过错误。
- 使用占位符编写示例，例如 `your-app-id`、`ALIPAY_PRIVATE_KEY` 和 `https://example.com/api/payment/notify/alipay`。

## 先检查再修改

1. 搜索现有支付实现、订单模型和权益发放路径，不要猜文件位置：

   ```bash
   rg -n "alipay|trade\.precreate|trade\.query|notify|callback|order.*status|credit|entitlement" src
   ```

2. 识别运行时、框架、金额单位、订单状态机、数据库事务能力和已有支付抽象。
3. 只检查环境变量是否存在和长度是否合理，禁止打印值；确认密钥文件、证书和 `.env` 未被 Git 跟踪。
4. 优先使用支付宝官方 SDK；仅在 Cloudflare Workers 等运行时不兼容时，用 Web Crypto 实现最小协议层。
5. 修改前先读 [协议与排障参考](references/protocol-and-debugging.md)，尤其是请求签名与通知验签的不同过滤规则。

## 实现流程

### 1. 建立配置边界

- 仅从服务端读取 `ALIPAY_APP_ID`、`ALIPAY_PRIVATE_KEY`、`ALIPAY_PUBLIC_KEY`、网关和通知地址。
- 明确区分三种材料：应用私钥用于请求加签；应用公钥上传支付宝开放平台；支付宝公钥用于响应与通知验签。
- 固定生产网关为官方配置值，显式区分沙箱与生产环境，禁止自动回退到另一个环境。
- 在启动或首次调用时验证配置形状，错误信息只指出缺少哪个变量或密钥格式，不回显内容。

### 2. 预创建二维码订单

1. 先创建本地待支付订单，生成全局唯一且可追踪的 `out_trade_no`。
2. 从服务端商品或套餐配置计算金额，不信任前端传入的金额、权益数量或标题。
3. 调用 `alipay.trade.precreate`，至少提供 `out_trade_no`、两位小数字符串 `total_amount`、`subject`，并设置公开 HTTPS `notify_url`。
4. 对请求原文做 RSA2 加签。请求加签只排除 `sign`，必须保留 `sign_type=RSA2`。
5. 检查业务响应 `code === "10000"` 且存在 `qr_code`；向前端返回二维码内容和本地订单号，不返回密钥、签名原文或完整网关响应。
6. 在前端用成熟 QR 库渲染 `qr_code` 内容。不要用 `data:text/html` 跳转顶层页面，也不要把支付宝返回的表单 HTML 当二维码。

### 3. 处理异步通知

1. 只接受支付宝规定的表单请求，按框架方式解析一次 `application/x-www-form-urlencoded`。
2. 用支付宝公钥验证 RSA2 签名；不要使用应用公钥，也不要复用请求签名的参数过滤函数。
3. 验签通过后再校验 `app_id`、`out_trade_no`、`total_amount`、订单归属和可用的卖家标识。
4. 仅处理 `TRADE_SUCCESS` 或 `TRADE_FINISHED`，并调用统一的幂等“确认支付”服务。
5. 成功完成后返回纯文本 `success`；处理失败返回非 `success`，让支付宝按策略重试。

### 4. 主动查询与前端轮询

- 让二维码页面以本地订单号轮询自己的状态接口，限制频率、超时和订单所有权。
- 在通知延迟或丢失时调用 `alipay.trade.query` 对账；只信任验签成功且订单、金额匹配的支付宝结果。
- 让通知与主动查询复用同一个幂等确认函数，禁止各自实现权益发放。
- 在订单已支付但权益缺失时执行可审计修复，不能因为状态已是 paid 就直接返回。

### 5. 保证幂等与一致性

- 在数据库事务中执行待支付到已支付的状态转换和权益流水写入。
- 为订单号与权益类型建立唯一约束，重复通知、重复轮询和并发请求只能发放一次。
- 保留必要的非敏感审计字段，例如支付宝交易号、金额、状态、确认来源和时间；不要保存完整回调。
- 拒绝金额、App ID、订单归属或商品快照不匹配的通知，并记录脱敏告警。

## Cloudflare Workers 要点

- 使用 `wrangler secret put` 或控制台 Secret 保存凭据，不要放入 `wrangler.toml` 的公开 `vars`。
- 使用 Web Crypto 的 `RSASSA-PKCS1-v1_5` 与 `SHA-256` 实现 RSA2；私钥导入为 PKCS#8，公钥导入为 SPKI。
- 兼容 Secret 中的真实换行和字面量 `\n`，但禁止在日志中输出标准化后的 PEM。
- 先对未编码的规范字符串签名，再做 URL/form 编码；禁止对已编码字符串加签或二次解码通知字段。
- 用 `Asia/Shanghai` 生成网关要求的时间格式，并确认部署时钟与环境正确。

## 验证门槛

- 添加确定性单元测试，断言请求签名原文包含 `sign_type=RSA2`，只排除 `sign`。
- 使用测试时动态生成的密钥对验证签名，不向仓库提交固定私钥或真实证书。
- 覆盖合法/非法通知、金额不匹配、App ID 不匹配、重复通知、重复轮询和“已支付但权益缺失”。
- 运行项目最快的类型检查、支付专项测试和构建；Cloudflare 项目再运行 Worker 构建检查。
- 部署前执行敏感信息扫描，并逐项检查暂存区；禁止在脏工作树中使用 `git add .`。
- 生产烟测只创建最低风险测试订单，确认能获得 `qr_code`、页面能显示二维码、支付后订单最终一致；不要在公开日志中粘贴响应。

## 排障顺序

1. 先保留支付宝 `code`、`sub_code`、`sub_msg` 和脱敏 trace ID，区分网关验签失败、业务失败与前端渲染失败。
2. 遇到“验签出错”时，先比较规范字符串字段集合，再检查密钥角色和格式；不要先换密钥。
3. 遇到“没有二维码”时，确认调用的是 `alipay.trade.precreate` 且成功响应中读取的是 `qr_code`。
4. 遇到“支付成功未到账”时，依次检查通知可达性、通知验签、订单/金额校验、主动查询和幂等权益流水。
5. 需要字段级诊断、测试矩阵或 Cloudflare 检查时，读取 [协议与排障参考](references/protocol-and-debugging.md)。

