华为支付-免密支付接入签约代扣场景开发步骤

embedded/2025/2/9 9:43:48/

一、预签约(服务器开发)

1.开发者按照商户模型调用预直连商户预签约或服务商预签约接口获取preSignNo构建签约信息参数contractStr。

为保证支付订单的安全性和可靠性需要对请求body和请求头PayMercAuth对象内的入参排序拼接进行签名。请参考排序拼接和签名示例代码。

以下为开放API接口请求及contractStr构建示例代码片段:

import com.huawei.petalpay.paymentservice.apiservice.client.model.BaseGwRspWithSign;
.import com.huawei.petalpay.paymentservice.apiservice.client.model.PreSignRequestV2;
.import com.huawei.petalpay.paymentservice.apiservice.client.model.PreSignResponse;
.import com.huawei.petalpay.paymentservice.core.client.DefaultPetalPayClient;
.import com.huawei.petalpay.paymentservice.core.client.PetalPayClient;
.import com.huawei.petalpay.paymentservice.example.common.CommonResponse;
.import com.huawei.petalpay.paymentservice.example.common.MercConfigUtil;
.
.public class MercApiController {
.    private static PetalPayClient payClient = new DefaultPetalPayClient(MercConfigUtil.getMercConfig());
.    /**
.     * 预签约接口调用
.     */
.    public CommonResponse contractPreSignAppV2() {
.        // 组装对象
.        PreSignRequestV2 preSignReq = getPreSignRequestV2();
.        PreSignResponse response = null;
.        try {
.            response = payClient.execute("POST", "/api/v2/contract/presign/app", PreSignResponse.class, preSignReq);
.        } catch (Exception e) {
.            // todo 异常处理
.            log.error("request error ", e);
.            return CommonResponse.buildErrorRsp(e.getMessage());
.        }
.        if (!validResponse(response)) {
.            // todo 异常处理
.            log.error("response is invalid ", response);
.            return CommonResponse.buildFailRsp(response);
.        }
.        return CommonResponse.buildSuccessRsp(payClient.buildContractStr(response.getPreSignNo()));
.    }
.    public static boolean validResponse(BaseGwRspWithSign rsp) {
.        return rsp != null && "000000".equals(rsp.getResultCode());
.    }
.    /**
.     * 预签约接口请求参数组装,商户请根据业务自行实现
.     */
.    private PreSignRequestV2 getPreSignRequestV2() {
.        return PreSignRequestV2.builder().appId(MercConfigUtil.APP_ID) // appId,需要配置为与商户绑定的正确的appId
.            .mercContractCode("pay-example-" + System.currentTimeMillis()) // 签约协议号,每次请求都要变,请将pay-example-修改为商户自己的订单前缀
.            .mercNo(MercConfigUtil.MERC_NO) // 商户号
.            .planId("100") // 协议模板ID,该模板ID是商户在向华为支付提交代扣权限申请时由华为支付生成。请填写正确的协议模板ID。
.            .callbackUrl("https://www.xxxxxx.com/hw/sign/callback") // 回调通知地址,通知URL必须为直接可访问的URL,要求为https地址。最大长度为512。请替换为格式正确的结果通知回调地址。
.            .build();
.    }
.}

二、拉起华为支付签约收银台(端侧开发)

商户客户端使用contractStr作为参数调用requestContract接口拉起Payment Kit签约收银台。

当接口通过.then()方法返回时,则表示当前订单支付成功,通过.catch()方法返回表示订单支付失败。当此次请求有异常时,可通过error.code获取错误码,错误码相关信息请参见错误码。示例代码如下:

.import { BusinessError } from '@kit.BasicServicesKit';
.import { paymentService } from '@kit.PaymentKit';
.import { common } from '@kit.AbilityKit';
.
.@Entry
.@Component
.struct Index {
.  context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
.  requestContractPromise() {
.    // use your own contractStr 
.    const contractStr = '{"appId":"***","preSignNo":"***"}';
.    paymentService.requestContract(this.context, contractStr)
.      .then(() => {
.        // succeeded in signing
.        console.info('succeeded in signing');
.      })
.      .catch((error: BusinessError) => {
.        // failed to sign
.        console.error(`failed to sign, error.code: ${error.code}, error.message: ${error.message}`);
.      });
.  }
.
.  build() {
.    Column() {
.      Button('requestContractPromise')
.        .type(ButtonType.Capsule)
.        .width('50%')
.        .margin(20)
.        .onClick(() => {
.          this.requestContractPromise();
.        })
.      }
.    .width('100%')
.    .height('100%')
.  }
.}

说明

·如果用户没有提前登录,系统会自动拉起华为账号登录页面让用户登录。

·签约成功,不建议以客户端返回作为用户的签约结果,需以服务器接收到的结果通知或者查询API返回为准。

三、签约结果回调通知(服务器开发)

支付成功后华为支付服务器会调用开发者提供的回调接口,将签约信息返回给开发者服务器,回调详细信息按商户模式请参见签约结果回调通知。

说明

回调接口是开发者调用预签约时的入参字段callbackUrl或签约模板配置的回调地址。

为保证信息合法性,商户服务器需要对返回的支付信息进行SM2验签,验签注意事项:

1.需直接使用通知的完整内容进行验签。

2.验签前需要对返回数据进行排序拼接,sign字段是签名值,排序拼接后的待验签内容需要排除sign字段。

3.验签公钥使用华为支付证书。

本文主要引用参考HarmonyOS官方文档


http://www.ppmy.cn/embedded/160772.html

相关文章

DeepSeek 提示词之角色扮演的使用技巧

老六哥的小提示:我们可能不会被AI轻易淘汰,但是会被“会使用AI的人”淘汰。 在DeepSeek的官方提示库中,有“角色扮演(自定义人设)”的提示词案例。截图如下: 在“角色扮演”的提示词案例中,其实…

【第一篇章】 C++ 初识

一、进门首先说 say hello 编写 helloworld.cpp 的文件&#xff0c;具体内容如下&#xff1a; #include <iostream> using namespace std; int main() {cout << "Hello, world!" << endl;return 0; }编译文件 g helloworld.cpp -o helloworld运…

python中的flask框架

Flask 是一个用Python编写的轻量级Web应用框架 基于WSGI和Jinja2模板引擎 被称为“微框架”&#xff0c;其核心功能简单&#xff0c;不捆绑数据库管理、表单验证等功能&#xff0c;而是通过扩展来增加其他功能 Flask提供最基本的功能&#xff0c;不强制使用特定工具或库 通…

认识网络安全

一 网络攻击链 踩点-工具准备-载荷投递-漏洞利用-释放载荷-建立通道-目标达成 简化下&#xff1a; 目标侦察&#xff1a;准确识别目标&#xff0c;收集目标详细信息&#xff0c;比如 网络、 邮箱、员工、社会关系、对外提供服务、漏洞 信息等&#xff0c;为 后续攻击做准备。…

Java实现状态模式

一、简介 1、定义 状态模式 (State Pattern)是一种行为型设计模式&#xff0c;允许对象在内部状态改变时改变它的行为。通过定义状态接口和具体状态类&#xff0c;将对象的状态和行为分开&#xff0c;使得状态改变时可以改变行为。 2、状态模式的结构 状态模式涉及以下几个角…

【C语言】C语言经典面试题详解

文章目录 引言1. 指针与数组1.1 指针与数组的区别1.2 指针数组与数组指针 2. 内存管理2.1 malloc与free2.2 内存泄漏与悬空指针 3. 函数指针3.1 函数指针的定义与使用3.2 回调函数 4. 结构体与联合体4.1 结构体的内存对齐4.2 联合体的使用场景4.3 位段 5. 预处理器与宏5.1 宏定…

直接插入排序

一&#xff1a;直接插入排序是什么。 二&#xff1a;如何实现直接插入排序 三&#xff1a;直接插入排序时间复杂度 一&#xff1a;直接插入排序它是排序得一种&#xff0c;其目的无非是将乱序通过排序排成有序的。 我们可以通过动画直观看什么是直接插入排序 这是我找的直接…

leetcode 1905. 统计子岛屿

题目如下 数据范围 示例 本题只要在遍历图二岛屿的时候检查图一对应位置是否是陆地即可。通过代码 class Solution { public:bool su true;int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {int n grid1.…