外观
云盘阅读
约 3316 字大约 9 分钟
会员办理接口云盘阅读
2026-10-21
提示
云盘阅读由渠道自己做办理页。页面动作、插码、IDaaS 录屏按本文接入。
办理只调用现有的 提交办理。接口返回的 redirectUrl 是 10086 支付地址,暂停录屏后再跳转。本产品不发短信,smsCode 固定传 000000。
支付完成先回到 wp.senins.cn 中间页,再跳回渠道页面。渠道页用提交办理返回的 orderId 调用 查询状态。同时传入 notifyUrl,接收 状态通知。
样例
办理过程见下方视频。页面源码可下载对照,插码和 IDaaS 按源码实现。
源码里的办理请求是我方页面自己的接口。渠道对接时改成 提交办理,请求字段按本文「提交办理」一节。
页面流程
页面按这个顺序做即可,交互和已上线的云盘阅读办理页保持一致:
- 落地页收集手机号,用户点击「立即办理」。
- 确认页展示业务信息,用户点击「确认订购」,拉起二次确认。
- 二次确认里点击「确认支付」,调用提交办理。
- 拿到
redirectUrl后跳转 10086 支付。 - 支付完成浏览器先回到
wp.senins.cn中间页,中间页解码rd后跳到渠道页面。渠道页用提交办理返回的orderId查询状态,PROCESSING间隔 2 秒以上再查,查到SUCCESS、FAIL、CANCEL后停止,并上报一次biz_result。状态通知到达时按同样结果更新页面。
注意事项
下面几条接错会直接导致插码验收或录屏对不上。
- 两个 traceId 分开存。 进页面自己生成一个 32 位业务 traceId(UUID 去掉横线),给埋点
trace_id、页面防护、订购凭证保全使用。authRecorderStart返回的才是录屏 traceId,只给暂停录屏和办理接口ext.traceId使用。两套值互不覆盖。 - 开始录屏只传
appId和pid。 录屏 traceId、sessionId 以成功回调为准,进页面时立刻调用。 - 确认支付按这个顺序。 先上报「订单提交」,再做订购凭证保全,再调提交办理。拿到
redirectUrl后先暂停录屏,暂停调用结束再跳转。 ext是 JSON 字符串。traceId填录屏 traceId,channelId填链接上的jTChannelId,redirectUrl填wp.senins.cn中间页地址,见「回跳中间页」。isOwn传false,payWay传2。- 渠道编码只用文末三组。 链接没带或不在这三组里,按
1000032022230300171(广点通)处理。埋点utm_source缺省也用这个编码。 - 支付地址补
Traceid。 返回的redirectUrl上如果没有Traceid、traceId、traceid,跳转前补上Traceid,值用录屏 traceId。 - 回跳必须走中间页。
ext.redirectUrl只能是wp.senins.cn域名。渠道自己的回跳地址做 Base64 后放到中间页参数rd,写法见「回跳中间页」。渠道地址末尾仍留空的_ecl_tail。 - 支付回来沿用业务 traceId。 地址栏里的 traceId 是录屏轨,给移动侧查录屏。回到页面后继续用进页面时的业务 traceId 埋点,不再调用开始录屏,也不调用继续录屏。
PROCESSING只表示拿到了支付地址。 记下返回的orderId。回到页面后调用查询状态,终态只上报一次biz_result。- 两套手机号加密分开做。 提交办理里的手机号按 接口列表 原样参与签名。插码里的
phone_number、user_unique_id用下方公钥做 RSA NoPadding 后再 Base64。 - 插码参数按原文。
app_id固定数字10000005,channel_domain固定https://dc.cmicapm.com:7080。member_type传数字。page_name与product_name相同。事件名、object_name、click_object按事件表原文上报。 - 先加载 CryptoJS。 挂到
window.CryptoJS之后,再加载 IDaaS JSSDK。
页面防护、录屏、凭证保全调用失败时,页面继续往后走,同时把失败日志留好。联调时要确认开始录屏的成功回调里已经拿到 traceId 和 sessionId。
插码
方案原文:插码埋点事件方案
SDK 说明:火山引擎 Web/JS SDK
初始化
app_id、channel_domain 使用下面的值。全埋点打开。
window.collectEvent('init', {
app_id: 10000005,
channel_domain: 'https://dc.cmicapm.com:7080',
log: true,
autotrack: true
})
window.collectEvent('start')使用 @datarangers/sdk-javascript 时,全埋点字段名是 auto_report,其余相同:
SDK.init({
app_id: 10000005,
channel_domain: 'https://dc.cmicapm.com:7080',
log: true,
auto_report: true
})
SDK.start()用户输完合法手机号后,把加密结果设为用户标识,后续事件都会带上:
window.collectEvent('config', {
user_unique_id: encryptedPhone,
user_unique_id_type: 'rsa_phone_id'
})手机号加密
算法:RSA / NoPadding,密文再做 Base64。明文手机号不能出现在埋点里。
公钥:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7UEOgJK80WRLyfndV9m99Py+rdTf0FEGEBe8swW7yg2bXYyVfLwzp3v23BLauaWKYCLlqUVaS+r44HelWptNxzF/Xxatj1Lwc1VNiDQKGQv3RNYb1H3bZZ4SYwGCderumDup4F2PsEk7aT95TLiU8H4S/jz3LrSiF7yD4yqRmDQIDAQAB
-----END PUBLIC KEY-----import forge from 'node-forge'
function encryptPhone(phone) {
const publicKey = forge.pki.publicKeyFromPem(RSA_PUBLIC_KEY)
const encrypted = publicKey.encrypt(phone, 'NONE')
return forge.util.encode64(encrypted)
}Java 侧对应 RSA/ECB/NoPadding,输出 Base64。
每条事件都带的字段
推广链接优先读 URL。缺省值按下表。
| 字段 | 取值 |
|---|---|
| module / module_name | 阅读会员办理 |
| module_code | reading_member_handle |
| page_name / page_title / product_name | 中国移动云盘阅读会员 |
| page_code | Mobile_Cloud_Drive_Reading_Member |
| page_url | 当前页面完整地址 |
| biz_version | 1.0.0 |
| product_id | 分配的推广编码,与办理接口 productId 相同 |
| member_type | 数字。1 联合会员,2 自有会员。缺省 1 |
| utm_source | URL 的 utm_source;没有则用 jTChannelId;再没有则 1000032022230300171 |
| utm_medium | URL 的 utm_medium。外部推广缺省 2303,端内推广用 3202 |
| utm_term | URL 的 utm_term,缺省 qy |
| trace_id | 业务 traceId |
| user_unique_id / phone_number | 加密后的手机号。拿到手机号之后才带 |
| user_unique_id_type | rsa_phone_id |
button_click 和 biz_result 另外带 click_time,格式 YYYY-MM-DD HH:mm:ss。
事件表
事件名、object_name、click_object 按表内原文上报。同一个手机号的「输入手机号」只报一次。biz_result 一次办理只报一次。
本产品是话费支付后跳转 10086,流程里没有获取验证码,对应事件不报。
| 时机 | 事件名 | object_name | click_object | object_type | 其他字段 |
|---|---|---|---|---|---|
| 进入办理页 | page_view | 公共字段 | |||
| 手机号输入完成(11 位) | button_click | 输入手机号 | Input_phone_number | input | phone_number 为加密手机号 |
| 点击立即办理 | button_click | 立即办理 | Click_Immediate_Handle | button | |
| 点击确认订购,拉起二次确认 | button_click | 二次确认 | Confirm_Secondary | button | |
| 点击确认支付,调用办理前 | button_click | 订单提交 | Confirm_Payment | button | 从这一刻开始计时,供 biz_result.msduration |
| 拿到最终办理结果 | biz_result | 办理结果 | handle_result | result | 见下方 |
| 离开页面 | page_duration | msduration:进入页面到离开的毫秒数,整数 |
biz_result 在查询到终态,或状态通知到达后上报,同一次办理只报一次:
| 字段 | 取值 |
|---|---|
| success_or_not | 布尔值。通知 SUCCESS 为 true,FAIL / CANCEL 为 false |
| order_seq | 提交办理返回的 orderId |
| msduration | 从「订单提交」到本次结果的毫秒数,整数 |
| fail_reason | 失败时带通知里的原因 |
页面上如果还有这些按钮,点击时补一条 button_click,名称使用下表,避免验收对不上:
| 按钮 | object_name | click_object |
|---|---|---|
| 暂不办理 | 暂不办理 | Cancel_Order |
| 取消支付 | 取消支付 | Cancel_Payment |
| 即将跳转 10086 | 跳转第三方支付页面 | Redirect_To_Pay |
| 重新支付 | 重新支付 | Retry_Payment |
| 刷新支付结果 | 刷新支付结果 | Refresh_Result |
上报示例:
window.collectEvent('button_click', {
module: '阅读会员办理',
module_name: '阅读会员办理',
module_code: 'reading_member_handle',
page_name: '中国移动云盘阅读会员',
page_title: '中国移动云盘阅读会员',
page_code: 'Mobile_Cloud_Drive_Reading_Member',
page_url: location.href,
biz_version: '1.0.0',
product_id: productId,
product_name: '中国移动云盘阅读会员',
member_type: 1,
utm_source: '1000032022230300171',
utm_medium: '2303',
utm_term: 'qy',
trace_id: businessTraceId,
user_unique_id: encryptedPhone,
user_unique_id_type: 'rsa_phone_id',
phone_number: encryptedPhone,
object_name: '订单提交',
click_object: 'Confirm_Payment',
button_name: 'Confirm_Payment',
object_type: 'button',
click_time: '2026-10-21 18:40:00'
})IDaaS 录屏
接入说明:AI+链接安全管理接入流程(通用版)
| 参数 | 值 |
|---|---|
| appId | 300013290901 |
| appKey | ECFB51E5950E614DCD0ED0301D793792 |
| pid | PID1789969353339 |
页面引入 SDK。CryptoJS 必须在前,并且能从 window.CryptoJS 取到:
<script src="crypto-js.min.js"></script>
<script src="https://h5auth.cmpassport.com/h5/js/jssdk_auth_idaas/wrapper_jssdk.min.js"></script>签名字符串(MD5,32 位小写十六进制):
appId + businessType + traceId + timestamp + traceId + version + appKeybusinessType 固定 8,version 固定 2.0。timestamp 为 17 位 yyyyMMddHHmmssSSS。
const APP_ID = '300013290901'
const APP_KEY = 'ECFB51E5950E614DCD0ED0301D793792'
const PID = 'PID1789969353339'
function getTimestamp() {
const d = new Date()
const pad = (n, len = 2) => String(n).padStart(len, '0')
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}${pad(d.getMilliseconds(), 3)}`
}
function generateSign(traceId, timestamp) {
const raw = `${APP_ID}8${traceId}${timestamp}${traceId}2.0${APP_KEY}`
return CryptoJS.MD5(raw).toString()
}凭证保全里的手机号用 AES 加密:密钥为 traceId 右侧补 0 后的前 16 位,AES/ECB/PKCS7。这里的 traceId 用业务 traceId。
function aesEncryptPhone(phone, traceId) {
const key = CryptoJS.enc.Utf8.parse(traceId.padEnd(16, '0').slice(0, 16))
return CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(phone), key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString()
}1. 进入页面:防护并开始录屏
先用业务 traceId 做实时页面防护:
const businessTraceId = crypto.randomUUID().replace(/-/g, '')
const timestamp = getTimestamp()
YDRZAuthLoginWrapper.getTokenInfoMkt({
data: {
appId: APP_ID,
pid: PID,
traceId: businessTraceId,
timestamp,
version: '2.0',
businessType: '8',
sign: generateSign(businessTraceId, timestamp)
},
success(res) {},
error(err) {}
})接着开始录屏。入参只有 appId 和 pid:
YDRZAuthLoginWrapper.authRecorderStart({
data: {
appId: APP_ID,
pid: PID
},
success(res) {
recorderTraceId = res.traceId || res.traceid || ''
sessionId = res.sessionId || res.sessionid || recorderTraceId
},
error(err) {}
})recorderTraceId、sessionId 存到 sessionStorage,跳转支付回来还要用。
2. 确认支付:订购凭证保全
用户点击「确认支付」、调用提交办理之前调用。blockSelector 写成页面上 loading、toast、遮罩的选择器,避免截进这些浮层。保全超过约 3.5 秒仍无回调时,继续调用办理接口。
const timestamp = getTimestamp()
YDRZAuthLoginWrapper.authSnapshot({
data: {
userPhone: aesEncryptPhone(phone, businessTraceId),
version: '2.0',
traceId: businessTraceId,
sign: generateSign(businessTraceId, timestamp),
timestamp,
appId: APP_ID,
pid: PID,
blockSelector: '.toast, .mask, .loading'
},
success(res) {},
error(err) {}
})3. 拿到支付地址:暂停录屏再跳转
traceId、sessionId 都用开始录屏的返回值。
function pauseThenJump(payUrl) {
const jump = () => { location.href = payUrl }
YDRZAuthLoginWrapper.authRecorderPause({
data: {
traceId: recorderTraceId,
sessionId: sessionId
},
success: jump,
error: jump
})
}办理接口返回失败、用户未跳到 10086 时,同样调用一次暂停录屏。
支付地址示例补参:
const url = new URL(redirectUrl)
if (!url.searchParams.has('Traceid') && !url.searchParams.has('traceId') && !url.searchParams.has('traceid')) {
url.searchParams.set('Traceid', recorderTraceId)
}
pauseThenJump(url.toString())回跳中间页
办理接口要求 ext.redirectUrl 的域名必须是 wp.senins.cn,不能填渠道自己的页面。
支付完成后浏览器先打开中间页。中间页读取参数 rd,Base64 解码后跳转到渠道页面。渠道页再用 orderId 查询办理结果。
中间页:
https://wp.senins.cn/oeh/equity/handle/mobile-cloud-read/redirect?rd=<Base64>
rd 是渠道回跳地址的 Base64,放入链接时做 encodeURIComponent。渠道回跳地址带上本次办理标识(如 channelTxId),参数最后加空的 _ecl_tail。
const channelReturnUrl = 'https://channel.example.com/cloud-read?step=waiting&channelTxId=CHANNEL_TX_ID&_ecl_tail='
const redirectUrl =
'https://wp.senins.cn/oeh/equity/handle/mobile-cloud-read/redirect?rd=' +
encodeURIComponent(btoa(channelReturnUrl))上面得到的 redirectUrl 写入 ext.redirectUrl。
上游若把 ECL 流水号无分隔符粘在 rd 末尾,中间页会去掉这段流水号再解码,并填入渠道地址里为空的 _ecl_tail。
提交办理
接口、签名、公共参数见 提交办理。本产品额外约定如下。
| 字段 | 是否必须 | 取值 |
|---|---|---|
| smsCode | 是 | 固定 000000 |
| smsKey | 否 | 不传 |
| notifyUrl | 是 | 接收 状态通知 的地址 |
| channelTxId | 是 | 渠道侧本次办理单号 |
| sourceUrl | 是 | 当前办理页完整地址,带上 jTChannelId |
| adPlatform | 是 | 投放平台,如 广点通、巨量引擎、磁力引擎 |
| appName | 是 | 用户当前所在 App 名称 |
| appPackage | 是 | App 包名,英文,如 com.tencent.mm |
| ext | 是 | 下表对象经 JSON.stringify 后的字符串 |
ext 对象:
| 字段 | 类型 | 取值 |
|---|---|---|
| traceId | string | authRecorderStart 返回的录屏 traceId |
| channelId | string | 链接参数 jTChannelId,见文末编码 |
| redirectUrl | string | https://wp.senins.cn 上的中间页地址,rd 为渠道回跳地址的 Base64,见「回跳中间页」 |
| isOwn | boolean | false |
| payWay | number | 2,话费支付 |
请求示例:
{
"appId": "",
"sign": "",
"data": {
"phone": "13800138000",
"productId": "分配的推广编码",
"smsCode": "000000",
"channelTxId": "渠道订单号",
"notifyUrl": "https://channel.example.com/notify",
"adPlatform": "广点通",
"appName": "微信",
"appPackage": "com.tencent.mm",
"sourceUrl": "https://channel.example.com/cloud-read?jTChannelId=1000032022230300171",
"ext": "{\"traceId\":\"录屏traceId\",\"channelId\":\"1000032022230300171\",\"redirectUrl\":\"https://wp.senins.cn/oeh/equity/handle/mobile-cloud-read/redirect?rd=aHR0cHM6Ly9jaGFubmVsLmV4YW1wbGUuY29tL2Nsb3VkLXJlYWQ%2Fc3RlcD13YWl0aW5nJmNoYW5uZWxUeElkPUNIQU5ORUxfVFhfSUQmX2VjbF90YWlsPQ%3D%3D\",\"isOwn\":false,\"payWay\":2}"
}
}返回里取出支付地址:
{
"code": 0,
"message": "",
"data": {
"orderId": "12345678",
"status": "PROCESSING",
"redirectUrl": "https://支付地址"
}
}有 redirectUrl 时记下 orderId,执行「暂停录屏 → 跳转」。回到页面后用这个 orderId 调用 查询状态。
SUCCESS 展示办理成功。FAIL、CANCEL 展示失败原因,并暂停录屏。提交办理当次就返回 FAIL 或 CANCEL、用户还没跳到 10086 时,同样暂停录屏并上报 biz_result。
状态通知的报文见 状态通知。查询和通知只要有一边先到终态,就更新页面并上报一次 biz_result。
渠道编码
推广链接带参数 jTChannelId。办理 ext.channelId、埋点 utm_source(URL 未单独传 utm_source 时)使用同一个值。
| jTChannelId | 渠道 |
|---|---|
| 1000032022230300171 | 广点通 |
| 1000032022230300172 | 巨量引擎 |
| 1000032022230300173 | 磁力引擎 |
未传或不在表内时,使用 1000032022230300171。