支付宝支付消息如何去除小程序入口
结论
通过支付宝小程序消息能力发送的提醒,属于小程序消息。消息卡片里的“小程序入口”由支付宝客户端统一生成,商家通常无法通过模板字段、接口参数或前端样式将其隐藏。
那些没有小程序入口的支付消息,一般不是小程序消息,而是支付宝根据真实交易生成的系统支付通知、商家收款提醒,或者由其他具有独立消息形态的产品能力发送。两者使用的消息渠道不同,无法通过修改现有小程序消息,将一种变成另一种。
为什么会显示小程序入口
小程序消息需要标明来源,也需要给用户提供返回对应小程序的路径。因此,支付宝客户端会根据消息类型渲染卡片,其中包括小程序名称、图标和进入入口等平台级元素。
开发者通常只能填写模板开放的业务字段,例如:
- 订单号
- 支付金额
- 支付时间
- 订单状态
- 备注信息
- 消息点击后的页面路径
卡片的整体结构和来源入口不属于模板字段。即使服务端不传页面路径,入口也不一定会消失。具体样式可能因支付宝客户端版本和消息模板类型而变化,但不应利用这些差异来规避入口。
没有入口的支付消息是如何产生的
这类消息通常由支付宝交易系统直接生成。例如,用户通过手机网站完成一笔支付宝交易后,支付宝可能向付款方展示支付结果,并向符合条件的商家账号或操作员发送收款提醒。
它们与开发者调用小程序消息接口发送的提醒并不是同一种能力:
| 消息类型 | 产生方 | 是否属于小程序消息 | 入口能否由商家控制 |
|---|---|---|---|
| 小程序模板或订阅消息 | 商家应用调用接口 | 是 | 通常不能隐藏 |
| 用户支付结果通知 | 支付宝交易系统 | 否 | 不能自定义 |
| 商家收款提醒 | 支付宝商家服务体系 | 否 | 通常只能配置接收人或提醒开关 |
| 商家自己的短信、邮件或内部通知 | 商家服务端 | 否 | 可以自行设计 |
能否收到支付宝原生的商家收款提醒,取决于签约产品、商家账号类型、交易归属、账号权限,以及支付宝当前开放的商家服务能力。小程序绑定了支付宝账号,并不意味着一定具备这项能力。
建议的处理方式
1. 不要再把小程序消息当作原生收款通知
如果只是想让财务或运营人员及时得知订单已经付款,应以后端异步通知为准,不要依赖支付宝客户端里的消息样式。
手机网站支付通常使用 alipay.trade.wap.pay 发起。创建支付请求时配置 notify_url,支付状态变化后,支付宝会向该地址发送异步通知。
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setNotifyUrl("https://example.com/alipay/notify");
request.setReturnUrl("https://example.com/payment/result");
request.setBizContent("""
{
"out_trade_no": "ORDER_202609130001",
"total_amount": "99.00",
"subject": "订单支付",
"product_code": "QUICK_WAP_WAY"
}
""");
String form = alipayClient.pageExecute(request).getBody();
return_url 用于用户支付完成后的页面跳转,notify_url 才是服务端确认支付结果的重要依据。即使用户关闭页面、网络中断,或者没有返回商家页面,后端仍应正常处理支付结果。
2. 在异步通知中完成验签和订单核对
下面只展示核心处理逻辑。SDK 初始化、异常处理和日志脱敏需要根据项目结构补充。
@PostMapping("/alipay/notify")
public String handleAlipayNotify(HttpServletRequest request) throws Exception {
Map<String, String> params = new HashMap<>();
request.getParameterMap().forEach((name, values) -> {
if (values != null && values.length > 0) {
params.put(name, String.join(",", values));
}
});
boolean verified = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
StandardCharsets.UTF_8.name(),
"RSA2"
);
if (!verified) {
return "failure";
}
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
String appId = params.get("app_id");
String sellerId = params.get("seller_id");
// 必须查询本地订单并核对:
// 1. app_id 是否为当前应用
// 2. seller_id 是否为预期收款方
// 3. total_amount 是否与订单金额一致
// 4. 订单是否已经处理,避免重复入账
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
paymentService.markPaidIdempotently(
outTradeNo,
tradeNo,
new BigDecimal(totalAmount),
appId,
sellerId
);
}
return "success";
}
验签成功并不代表订单一定有效。系统还要核对应用、收款方、订单号和金额,并通过唯一约束或状态机保证幂等。完成业务处理后,再返回支付宝要求的成功响应。如果处理失败,不要提前返回成功。
3. 从后端发送内部提醒
确认支付成功后,可以根据实际需要发送:
- 企业内部机器人消息
- 短信
- 邮件
- App 推送
- 财务系统待处理通知
- 订单后台实时提醒
这些提醒由商家自行控制,不会带有支付宝小程序入口,但也不会出现在支付宝的系统支付消息中。
4. 检查支付宝商家侧的收款提醒
如果必须在支付宝客户端内接收不带小程序入口的提醒,需要检查对应商家账号的收款通知、商家服务或操作员通知设置,并确认交易确实归属于该商家主体。
如果后台没有相关配置,可以向支付宝开放平台或商家客服提供以下信息进行核实:
- 应用
app_id - 签约产品名称
- 商家账号类型
- 交易收款主体
- 希望接收提醒的账号及其角色
- 示例交易号
trade_no - 目标消息的截图和出现位置
不要申请小程序消息模板来模拟系统支付通知。即使文案相同,两者的消息来源、显示样式和跳转行为仍然不同。
能否去除现有消息中的入口
一般不能。可以考虑以下做法:
- 继续使用小程序消息,接受平台提供的入口。
- 停止发送该小程序消息,改用服务端异步通知和内部提醒。
- 如果具备相应资格和产品能力,启用支付宝原生的商家收款提醒。
不建议通过传入空路径、无效页面路径或特殊字符来隐藏入口。这些做法无法保证显示效果,还可能导致点击异常、模板审核失败或用户体验问题。
支付状态确认和消息提醒应分开处理。支付结果以服务端验签和订单核对为准,提醒渠道则根据接收对象单独选择。
备注:内容仅供参考。
