HarmonyOS 7 互动卡片重复提交:两个入口同时点击,服务端怎样识别同一次动作
页面按钮禁用只能约束一个界面。卡片和应用页同时发起同一个动作时,各自的防抖状态互不相通。需要把操作身份带到结果保存的位置,而不是只在界面保存一个loading变量。
适配范围
这里的回执表只演示同步单进程行为,不是可直接部署的服务端。生产需要唯一索引、事务和持久化;异步副作用或崩溃窗口必须另行处理。JSON指纹要求字段顺序固定,正式协议应明确规范序列化。
案例一
卡片与应用页使用同一个操作标识:两次提交返回同一回执,副作用只执行一次。
案例二
错误复用了操作标识:相同key却携带不同item,必须冲突报错,不能返回上一次操作的成功回执。
可以运行的实现
export class ReceiptStore { receipts = new Map(); submit(key, payload, perform) { const fingerprint = JSON.stringify(payload); const old = this.receipts.get(key); if (old) { if (old.fingerprint !== fingerprint) throw Error('key_payload_conflict'); return old.result; } const result = perform(payload); this.receipts.set(key, {fingerprint, result}); return result; } }复现与断言
把实现与以下测试放进同一个example.mjs,执行node example.mjs。断言失败会报错,全部通过正常退出。这些断言已经在本地Node.js执行;它们不代表SDK编译、真机接口调用或性能实测已经通过。
import assert from 'node:assert/strict'; let calls = 0; const service = new ReceiptStore(); const action = {item:'A',count:1}; const perform = () => ({receipt:++calls}); assert.equal(service.submit('operation-1',action,perform).receipt, 1); assert.equal(service.submit('operation-1',action,perform).receipt, 1); assert.equal(calls, 1); assert.throws(() => service.submit('operation-1',{item:'B',count:1},perform)); assert.equal(service.submit('operation-2',action,perform).receipt, 2);方案取舍
界面防抖改善体验,但不提供跨入口幂等。操作key与参数指纹组合能发现重复与误复用;单纯按参数去重会误伤两次合法的相同操作。
接入时别漏掉这些边界
这里的回执表只演示同步单进程行为,不是可直接部署的服务端。生产需要唯一索引、事务和持久化;异步副作用或崩溃窗口必须另行处理。JSON指纹要求字段顺序固定,正式协议应明确规范序列化。
复用时把输入获取与纯逻辑分开:界面、系统事件和服务请求负责取得真实输入,独立模块负责给出判断或保存状态。保留上述两个案例作为回归测试,并对失败原因记录最少必要日志,不记录文件内容、账号凭据或其它敏感数据。升级SDK后重新核对支持设备、接口版本与错误行为,而不是只改目标版本号。
官方资料
HarmonyOS 官方能力入口
示例验证环境为Node.js,验证范围是应用侧逻辑。本文不将示例当作系统接口接入代码;具体接口的支持设备、最低版本和调用方式,以所用SDK对应的官方文档为准。