自定义组件UDF接入管理
一、自定义组件UDF说明
自定义组件简称 UDF(User-Defined Functions),取名于常用的数据开发平台所使用的用户自定义函数。以下均以 UDF 代替自定义组件。
UDF 接入分为配置和执行两部分,配置用于界面管理、画布配置组件,执行用于旅程执行过程中的回调(执行部分和 WebHook 相似)。
二、UDF配置接入文档
为了与Quick Audience对接,您需要开发一个HTTP Server。注意是Post请求,请求超时时间为10秒。Quick Audience发起的HTTP请求和接入方回执请求约定如下通用参数,为必传项。
2.1 系统间的流转接口图
① 为“开发线下提供配置信息”如下所示
② 为iframe页面跳转,跳转到外部系统中
③ API 接口:通过令牌获取用户信息;同时需要将结果返回给iframe页面。
④ API 接口:通过令牌获取标签信息;同时需要将结果返回给iframe页面。
⑤ 前端提交数据到iframe嵌入页面中的 API,由外部系统后台通过 ⑥ 提交数据到 QA
⑥ API 接口:将配置信息提交到 QA,QA 根据选择的标签信息进行流程执行
2.1.1 产品界面配置 UDF 组件信息
字段填写限制:
字段 | 限制 |
嵌入页面地址 | 组件内需要iframe嵌入的链接地址,必须是合法的完整地址,包含使用的协议(如http或https),建议使用https,提高信息传输的安全性。 |
icon URL | 组件显示icon,建议尺寸21 * 21px |
请求地址 | 要接受消息推送的接口地址,必须是合法的完整地址,包含使用的协议(如http或https),建议使用https,提高信息传输的安全性。 |
回执设置 | 回执设置将以接口形式将营销结果返回到QA,需要配置回执结果字段,将在自动化营销中可通过结果判断基于回执结果分流。 |
AES密钥 | AES密钥长度可以为128、192或256位,对应字符为16、24、32位。 |
2.1.1.1 配置的原始 JSON 信息
{
"name":"自定义组件名称",
"type":"marketing", //自定义组件类别:当前只支持 marketing -> 营销组件
"version":"版本号", // 默认 1.0
"endpoint":"自定义组件目标域名 以http或https开头,如:http://demo.com/二级路径 跳转至 $endpoint/index.html",
"iconUrl":"icon地址",
"enable": true // true or false是否启用
"accessKey":"组件鉴权accessKey",
"accessSecret":"组件鉴权accessSecret",
"metaData":{ // 元数据信息,不通类型组件 metaData 格式不同
"allowIDType":"该组件支持用户ID类型,如 mobile | email | idfa | imei等",
"encryptionMethod":"推送营销消息 加密算法 null | encryptionMethod",
"sendParam":{
"batchSendUrl":"营销任务推送地址 以http或httpss开头,如 http://demo.com/send",
"batchLimit":100, //批量推送条数限制 1~1000, 默认100
"timeout": 10, //请求超时时间(单位秒) 0 ~ 60, 默认10
"retryTimes":0, //失败重试次数 0 ~ 3, 默认0
"retryPeriod":0, //重试时间间隔(单位秒) 0 ~ 3600, 默认 0
},
"callbackParam":{//营销组件回执参数
"usableInHours": 3 * 24, //1 ~ 30 * 24,默认3 推送结果回执数据在多少天的时间内返回算有效,超过则丢弃
"clearInHours": 7 * 24, //1 ~ 365 * 24,默认 7 * 24 推送结果回执数据超过多少天后将被回收
"resultEnumList":[ //推送结果回执枚举列表, 默认 success & fail
{
"code":"success",
"name":"成功"
},
{
"code":"fail",
"name":"失败"
}
],
"extParams": {
"extParam1": "拓展参数列头001", //在效果分析中展示的列名,拓展字段01
"extParam2": "拓展参数列头002", //在效果分析中展示的列名,拓展字段02
"extParam3": "拓展参数列头003" //在效果分析中展示的列名,拓展字段03
}
}
}
}
2.1.2 iframe 跳转
需要外部系统提供一个 iframe 页面,页面链接在上一步配置的endpoint中填写。
注意:会存在跨域问题,需要增加跨域支持,X-Frame-Options: allow-from https://example.com/
跳转 URL
/endPoint?comeFrom=xxx&qaEndpoint=xxx&token=xxx
返回结果
{
"success":true,
"errorDesc":"错误信息,可以为空"
}
2.1.3 API 接口:通过令牌获取用户信息
API:/openapi/v3/account/query?token=xxx
返回值:
{
"success": false,
"errorDesc": "",
"data": {
"organizationId":"组织 ID",
"organizationName":"组织名称",
"userId":"用户 ID",
"nickName":"用户昵称",
},
"@comment": {
"success": "/**\n * 枚举值:true | false\n */",
"errorDesc": "/**\n * 错误信息描述\n */",
"data": "/**\n * 用户信息\n */"
}
}
只有成功获取到用户信息,才说明正常可用,如果未获取到用户信息,渲染页面时应该返回 token 失效错误信息。
2.1.4 API 接口:保存UDF选择的人群、事件 id 等
API:/restapi/marketing/udf_component/genUdfComponentNode
入参:
{
"componentId": "1001",
"sourceId": "c1f5691dd5864479820c10c0089bece9 (这里传人群 id,事件 id)",
"sourceNodeId": "",
"nodeId": "83a2d328-030d-436a-b607-21da8ee2e34b",
"sourceType": 1 // 这里传类型,1是人群 2是事件
}
返回值:
{
"data": {
"nodeId": "83a2d328-030d-436a-b607-21da8ee2e34b",
"token": "zKBfv7flRQmhd+XP1l1uuKCjE6seEOq8l02cBFWWRr5xQoOUPxb3+tj+ZPctWDG4rM5vC2PMQLxG0Xw7Qw6TpsDfXSYFwD8kmTjpUOV4AjxQfZPfC5q0wPrEFhvgfjz9X1OKDu4V4p1oJnJcbt5nELidsVk6jxkbVwHEL8ezXcyXFRKbC+jVYxOwG5ElUhS0+hraAK5IiwR1XgZCarFgOGf5ZZo/Nacjrp5AP8HbF3tl4+thAjp8ZuMWTYXsBJbe"
},
"errorCode": null,
"errorDesc": null,
"exStack": null,
"opers": [],
"solution": null,
"success": true,
"traceId": "48d6e570-1918-47a4-83ee-27c3f32d3a99"
}
2.1.5 API 接口:通过令牌获取人群标签列表/事件属性列表 (依赖1.4)
API:/openapi/v3/udf_component/marketing/getNodeUsableLabels?token=xxx&nodeId=xxx&version=VERSION_2
返回值:
[
{
"id": "标签ID/属性ID",
"name": "标签名称/属性名称"
}
]
选择的标签/属性会在最终外调三方系统的时候作为参数传入。
2.1.6 前端提交数据到iframe嵌入页面中的 API
该页面参数由三方自行定义,最终执行时,由 QA 调用到三方后,三方自行执行。但需要将选中的 QA 标签通过⑥的接口回传给 QA。
2.1.7 提交 UDF 配置信息
API:/openapi/v3/udf_component/marketing/saveOrUpdateNodeConfig?token=xxx
请求体:
{
"nodeId": "节点ID",
"nodeName": "节点名称",
"labelIdList": [
"标签ID1",
"标签ID2"
]
}
返回值:无返回值,判断 HTTP 状态200即可
三、UDF执行接入文档
系统流转图如下所示
3.1 节点执行请求
为了与Quick Audience对接,您需要开发一个HTTP Server。注意是Post请求,请求超时时间为10秒。Quick Audience发起的请求和接入方回执请求约定如下通用参数,为必传项。
请求URL:{UDF配置的 sendParam.batchSendUrl }
请求Header信息
Header信息读取后需要通过java.net.URLDecoder#decode(java.lang.String, java.lang.String)
,编码为UTF-8。
v=4 // 固定参数,用于区分新老版本,新版本为4,老版本没有这个字段
请求体:
请求入参 | 备注 | |||
参数 | 参数 | 类型 | 是否必须 | |
请求时间戳 | time | Long | 是 | |
请求ID | requstId | String | 是 | |
组件ID | componentId | String | 是 | |
组件accessKey | accessKey | String | 是 | AES密钥长度可以为128、192或256位,对应字符为16、24、32位。 |
消息体加密算法 | encryptionMethod | String | 否 | 默认不加密 null 目前仅支持AES 加密,加密和填充方式为:AES/ECB/PKCS5Padding |
签名 | signature | String | 是 | time + componentId + accessKey + accessSecret 经过hmac 加密后 注:签名算法和 WebHook 一样。 |
消息体 | data | String | 是 | 经过encryptionMethod加密后消息体:
|
请求体示例:
{
"time": 0,
"requestId": "111",
"componentId": "111",
"accessKey": "111",
"signature": "111",
"encryptionMethod": [
"AES"
],
"data": "字符串格式,详细格式如下"
}
// data 的格式
{
"jobId": "",
"jobName": "",
"nodeId": "",
"nodeName": "",
"componentName": "",
"taskId": "",
"taskStartTimestamp": 0,
"nodeStartTimestamp": 0,
"data": {
"messageId": "",
"customerList": [
{
"customerId": "",
"labels": {},
"featureMap": {
"回执字段":"原样带回"
},
"processInfo": {
"processInstanceId": "新版:旅程周期中,每个用户的旅程实例ID",
"processInstanceStartTime": "新版:旅程周期中,每个用户的旅程实例开始时间,时间戳格式",
"processNodeInstanceId": "新版:旅程节点实例ID(每次不同)",
"processNodeInstanceStartTime": "新版:旅程周期中,每个用户的旅程的节点实例开始时间,时间戳格式",
"groupName":"nodeId:nodeName:groupResult(node.result),groupName(node.resultExt);nodeId:nodeName:groupResult(node.result),groupName(node.resultExt)",
"@comment":{
"groupName" : "节点id:节点名称(界面配置的):分组结果(随机分组的百分比数字,两位小数):分组名称(界面配置的);多个用分号隔开"
}
}
"@comment": {
"featureMap": "/**\n * 拓展字段,异步回执时下游必须带回\n */"
}
}
]
},
"activityId": "",
"activityName": "",
"subActivityId": "",
"subActivityName": "",
"processId": "",
"processName": "",
"processInstanceId": "",
"processInstanceName": "",
"processInstanceStartTime": "",
"processNodeId": "",
"processNodeName": "",
"processNodeInstanceId": "",
"processNodeInstanceStartTime": "",
"groupId": "",
"groupName": "",
"@comment": {
"activityId": "/**\n * 活动ID\n */",
"activityName": "/**\n * 活动名称\n */",
"subActivityId": "/**\n * 子活动ID\n */",
"subActivityName": "/**\n * 子活动名称\n */",
"processId": "/**\n * 旅程ID(自动化ID);活动ID\n */",
"processName": "/**\n * 旅程名称(自动化名称);活动名称\n */",
"processInstanceId": "/**\n * 旅程实例ID;活动实例ID\n */",
"processInstanceName": "/**\n * 活动实例名称(有实例的时间)\n */",
"processInstanceStartTime": "/**\n * 活动实例开始时间\n */",
"processNodeId": "/**\n * 活动节点ID\n */",
"processNodeName": "/**\n * 活动节点名称\n */",
"processNodeInstanceId": "/**\n * 活动节点实例ID\n */",
"processNodeInstanceStartTime": "/**\n * 活动节点实例开始时间\n */",
"groupId": "/**\n * ABTest分组ID(暂未实现,为空)\n */",
"groupName": "/**\n * ABTest分组名称(暂未实现,为空)\n */"
}
}
返回值:
{
"success": true,
"errorDesc": "错误信息",
"customerList": [
{
"messageId": "消息 ID",
"customerId": "客户 ID",
"returnType": "回执结果,该结果和回执结果一样,如果有则直接当做回执结果,如果不希望直接填写回执结果,不要传递",
"returnMessage": "回执消息,长度限制255,超过会自动截取掉"
}
]
}
3.1.1 鉴权方式
签名算法
long sendTime = System.currentTimeMillis();
// 组件id
// 组件ak
// 组件sk
String sign = getSignatureByHmacSHA1(sendTime, componentModel.getComponentId(), componentModel.getAccessKey(), componentModel.getAccessSecret());
public static String getSignatureByHmacSHA1(long time, String prametersString, String accessKey, String accessSecret) {
String str = time + prametersString + accessKey;
return HmacUtils.hmacSha256Hex(accessSecret, str.replaceAll("\\s+", ""));
}
3.2回执上报
接入方执行营销任务后,向Quick Audience上报回执,反馈营销消息的发送结果。
HTTP请求URL:
API:/restapi/marketing2/udfComponent/receiveCallback?
请求体:
{
"time": 0,
"componentId": "UDF组件ID",
"signature": "签名",
"data": "加密后回执信息,字符串",
"@comment":{
"time":"回执时间戳,毫秒"
}
}
// data的原始格式
{
"nodeId": "节点ID",
"taskId": "任务ID",
"customerList": [
{
"messageId": "消息 ID",
"customerId": "客户 ID",
"returnType": "回执结果",
"sendTimestamp": 0,
"featureMap": {
"请求参数": "原样回传回来"
}
"@comment": {
"messageId": "/**\n * 消息ID,QA推送的时候 会带上这个ID\n */",
"customerId": "/**\n * 用户ID\n */",
"returnType": "/**\n * 回执结果\n */",
"sendTimestamp": "/**\n * 消息推送时间\n */",
"featureMap": "发送请求时的参数,需要在回执时原样带回来"
},
"extParam1": "拓展参数001-自定义返回值",
"extParam2": "拓展参数002-自定义返回值",
"extParam3": "拓展参数003-自定义返回值"
}
],
"@comment": {
"nodeId": "/**\n * 节点ID\n */",
"taskId": "/**\n * 任务ID\n */",
"customerList": "/**\n * 回执用户/粉丝列表\n */"
}
}
返回值:
{
"success": true,
"errorDesc": "",
"@comment": {
"success": "/**\n * 枚举值:true | false\n */",
"errorDesc": "/**\n * 错误信息描述\n */",
"data": "/**\n * 用户信息\n */"
}
}