集成 HyperPay 后未获得有效支付结果
结论
shopperResultUrl 被拒绝的原因是:
com.share.flutter_app://result
这个地址的 URI scheme com.share.flutter_app 含有下划线 _。标准 URI 语法规定,scheme 只能使用字母、数字、加号 +、连字符 - 和点号 .,不能使用下划线。
可以改成:
com.share.flutterapp://result
或者:
com.share.flutter-app://result
Android 和 iOS 也要注册完全相同的 Deep Link scheme。
notificationUrl 应填写支付服务器可以访问的公网 HTTPS 地址,不能使用 App Deep Link。HyperPay 会通过这个地址发送服务端异步支付通知,例如:
https://api.example.com/webhooks/hyperpay
为什么会出现这个错误
响应中的两个参数错误彼此相关:
shopperResultUrl: invalid uri
notificationUrl: Notification url must be present if shopperResultUrl is not a valid url
第一个错误说明 HyperPay 无法将下面的值解析为有效 URI:
com.share.flutter_app://result
URI 的基本格式是:
scheme://host/path
按照通用 URI 语法,scheme 必须符合:
[A-Za-z][A-Za-z0-9+.-]*
因此:
com.share.flutter_app // 无效,包含 _
com.share.flutterapp // 有效
com.share.flutter-app // 有效
com.share.flutter.app // 有效
由于 shopperResultUrl 无效,同时 HyperPay 没有收到可用的 notificationUrl,最终返回:
200.300.404
这个结果表示请求参数缺失或格式错误,不是最终的支付成功或失败状态。
正确配置 shopperResultUrl
创建 checkout 时,可以使用不带下划线的自定义 scheme:
shopperResultUrl=com.share.flutterapp://result
请求参数示例:
entityId=YOUR_ENTITY_ID
amount=10.00
currency=SAR
paymentType=DB
shopperResultUrl=com.share.flutterapp://result
使用表单编码时,需要对参数进行 URL 编码。例如:
curl -X POST "https://eu-test.oppwa.com/v1/checkouts" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "entityId=YOUR_ENTITY_ID" \
--data-urlencode "amount=10.00" \
--data-urlencode "currency=SAR" \
--data-urlencode "paymentType=DB" \
--data-urlencode "shopperResultUrl=com.share.flutterapp://result"
HyperPay 的接口地址、认证方式和必填字段可能因接入模式及运行环境而异,请以当前账户对应的官方集成文档为准。
在移动端注册 Deep Link
只修改接口参数还不够,App 也必须能处理相同的 URI。
Android
在目标 Activity 的 AndroidManifest.xml 中添加:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="com.share.flutterapp"
android:host="result" />
</intent-filter>
这段配置对应以下地址:
com.share.flutterapp://result
android:scheme 和 android:host 必须与传给 HyperPay 的地址一致。
iOS
在 Info.plist 中注册 URL scheme:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.share.flutterapp</string>
</array>
</dict>
</array>
如果使用 Flutter Deep Link 插件,还需要按插件要求配置事件监听。插件只能将回调 URI 交给应用,不能替代服务端的支付状态查询。
正确配置 notificationUrl
notificationUrl 是服务端 webhook 地址,需要满足以下条件:
- 使用公网可以访问的 URL;
- 优先使用 HTTPS;
- 不能填写
localhost、局域网地址或 App 自定义 scheme; - 接口能够接收 HyperPay 发出的通知请求;
- 收到通知后,再次向 HyperPay 查询并核验支付状态。
例如:
https://api.example.com/webhooks/hyperpay
参数可以这样填写:
shopperResultUrl=com.share.flutterapp://result
notificationUrl=https://api.example.com/webhooks/hyperpay
在本机开发时,通常需要部署测试 webhook,或者通过安全的 HTTPS 隧道临时开放本地接口。HyperPay 测试环境是否接受某类隧道域名,应以其实际校验规则为准。
如何可靠获得支付结果
shopperResultUrl 的作用只是将用户带回 App,不能直接证明支付成功。用户可能关闭页面、遇到网络中断,回调 URI 也可能被手动触发。
建议按以下流程处理:
- 服务端创建 checkout,并将 checkout ID 返回给 App。
- App 打开 HyperPay 支付组件。
- 支付流程结束后,App 收到
shopperResultUrl回调。 - App 将 checkout ID 或 SDK 返回的
resourcePath发给自己的服务端。 - 服务端调用 HyperPay 的支付状态查询接口。
- 服务端根据查询结果更新订单。
- 配置了
notificationUrl时,服务端还要处理异步通知,并通过幂等机制应对重复通知。
查询逻辑的伪代码如下:
async function verifyPayment(resourcePath) {
// resourcePath 应来自可信的支付流程,
// 并在服务端验证它是否属于当前订单。
const response = await hyperPayRequest(resourcePath, {
entityId: process.env.HYPERPAY_ENTITY_ID
});
return response.result;
}
App 收到下面的地址后,不要直接将订单标记为已支付:
com.share.flutterapp://result
最终支付状态应以服务端查询到的 HyperPay 结果为准。
注意事项
- 不要在
shopperResultUrl的 scheme 中使用_。 - 自定义 scheme、Android Manifest 和 iOS
Info.plist中的配置必须一致。 notificationUrl应指向服务端 HTTPS 接口,不能填写移动端 Deep Link。- 测试环境和生产环境应分别配置接口地址、凭据和 entity ID。
- 不要在 App 中保存访问令牌等服务端密钥。
- webhook 可能重复发送,订单更新必须具备幂等性。
- 判断支付结果时,应遵循当前 HyperPay 文档中的结果码规则,不能只看 HTTP 状态码或页面是否成功跳转。
备注:内容仅供参考。
