自定義組件UDF接入管理
一、自定義組件UDF說明
自定義組件簡稱 UDF(User-Defined Functions),取名于常用的數(shù)據(jù)開發(fā)平臺所使用的用戶自定義函數(shù)。以下均以 UDF 代替自定義組件。
UDF 接入分為配置和執(zhí)行兩部分,配置用于界面管理、畫布配置組件,執(zhí)行用于旅程執(zhí)行過程中的回調(diào)(執(zhí)行部分和 WebHook 相似)。
二、UDF配置接入文檔
為了與Quick Audience對接,您需要開發(fā)一個HTTP Server。注意是Post請求,請求超時時間為10秒。Quick Audience發(fā)起的HTTP請求和接入方回執(zhí)請求約定如下通用參數(shù),為必傳項(xiàng)。
2.1 系統(tǒng)間的流轉(zhuǎn)接口圖
① 為“開發(fā)線下提供配置信息”如下所示
② 為iframe頁面跳轉(zhuǎn),跳轉(zhuǎn)到外部系統(tǒng)中
③ API 接口:通過令牌獲取用戶信息;同時需要將結(jié)果返回給iframe頁面。
④ API 接口:通過令牌獲取標(biāo)簽信息;同時需要將結(jié)果返回給iframe頁面。
⑤ 前端提交數(shù)據(jù)到iframe嵌入頁面中的 API,由外部系統(tǒng)后臺通過 ⑥ 提交數(shù)據(jù)到 QA
⑥ API 接口:將配置信息提交到 QA,QA 根據(jù)選擇的標(biāo)簽信息進(jìn)行流程執(zhí)行
2.1.1 產(chǎn)品界面配置 UDF 組件信息
字段填寫限制:
字段 | 限制 |
嵌入頁面地址 | 組件內(nèi)需要iframe嵌入的鏈接地址,必須是合法的完整地址,包含使用的協(xié)議(如http或https),建議使用https,提高信息傳輸?shù)陌踩浴?/p> |
icon URL | 組件顯示icon,建議尺寸21 * 21px |
請求地址 | 要接受消息推送的接口地址,必須是合法的完整地址,包含使用的協(xié)議(如http或https),建議使用https,提高信息傳輸?shù)陌踩浴?/p> |
回執(zhí)設(shè)置 | 回執(zhí)設(shè)置將以接口形式將營銷結(jié)果返回到QA,需要配置回執(zhí)結(jié)果字段,將在自動化營銷中可通過結(jié)果判斷基于回執(zhí)結(jié)果分流。 |
AES密鑰 | AES密鑰長度可以為128、192或256位,對應(yīng)字符為16、24、32位。 |
2.1.1.1 配置的原始 JSON 信息
{
"name":"自定義組件名稱",
"type":"marketing", //自定義組件類別:當(dāng)前只支持 marketing -> 營銷組件
"version":"版本號", // 默認(rèn) 1.0
"endpoint":"自定義組件目標(biāo)域名 以http或https開頭,如:http://demo.com/二級路徑 跳轉(zhuǎn)至 $endpoint/index.html",
"iconUrl":"icon地址",
"enable": true // true or false是否啟用
"accessKey":"組件鑒權(quán)accessKey",
"accessSecret":"組件鑒權(quán)accessSecret",
"metaData":{ // 元數(shù)據(jù)信息,不通類型組件 metaData 格式不同
"allowIDType":"該組件支持用戶ID類型,如 mobile | email | idfa | imei等",
"encryptionMethod":"推送營銷消息 加密算法 null | encryptionMethod",
"sendParam":{
"batchSendUrl":"營銷任務(wù)推送地址 以http或httpss開頭,如 http://demo.com/send",
"batchLimit":100, //批量推送條數(shù)限制 1~1000, 默認(rèn)100
"timeout": 10, //請求超時時間(單位秒) 0 ~ 60, 默認(rèn)10
"retryTimes":0, //失敗重試次數(shù) 0 ~ 3, 默認(rèn)0
"retryPeriod":0, //重試時間間隔(單位秒) 0 ~ 3600, 默認(rèn) 0
},
"callbackParam":{//營銷組件回執(zhí)參數(shù)
"usableInHours": 3 * 24, //1 ~ 30 * 24,默認(rèn)3 推送結(jié)果回執(zhí)數(shù)據(jù)在多少天的時間內(nèi)返回算有效,超過則丟棄
"clearInHours": 7 * 24, //1 ~ 365 * 24,默認(rèn) 7 * 24 推送結(jié)果回執(zhí)數(shù)據(jù)超過多少天后將被回收
"resultEnumList":[ //推送結(jié)果回執(zhí)枚舉列表, 默認(rèn) success & fail
{
"code":"success",
"name":"成功"
},
{
"code":"fail",
"name":"失敗"
}
],
"extParams": {
"extParam1": "拓展參數(shù)列頭001", //在效果分析中展示的列名,拓展字段01
"extParam2": "拓展參數(shù)列頭002", //在效果分析中展示的列名,拓展字段02
"extParam3": "拓展參數(shù)列頭003" //在效果分析中展示的列名,拓展字段03
}
}
}
}
2.1.2 iframe 跳轉(zhuǎn)
需要外部系統(tǒng)提供一個 iframe 頁面,頁面鏈接在上一步配置的endpoint中填寫。
注意:會存在跨域問題,需要增加跨域支持,X-Frame-Options: allow-from https://example.com/
跳轉(zhuǎn) URL
/endPoint?comeFrom=xxx&qaEndpoint=xxx&token=xxx
返回結(jié)果
{
"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 */"
}
}
只有成功獲取到用戶信息,才說明正常可用,如果未獲取到用戶信息,渲染頁面時應(yīng)該返回 token 失效錯誤信息。
2.1.4 API 接口:保存UDF選擇的人群、事件 id 等
API:/restapi/marketing/udf_component/genUdfComponentNode
入?yún)?/b>:
{
"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 接口:通過令牌獲取人群標(biāo)簽列表/事件屬性列表 (依賴1.4)
API:/openapi/v3/udf_component/marketing/getNodeUsableLabels?token=xxx&nodeId=xxx&version=VERSION_2
返回值:
[
{
"id": "標(biāo)簽ID/屬性ID",
"name": "標(biāo)簽名稱/屬性名稱"
}
]
選擇的標(biāo)簽/屬性會在最終外調(diào)三方系統(tǒng)的時候作為參數(shù)傳入。
2.1.6 前端提交數(shù)據(jù)到iframe嵌入頁面中的 API
該頁面參數(shù)由三方自行定義,最終執(zhí)行時,由 QA 調(diào)用到三方后,三方自行執(zhí)行。但需要將選中的 QA 標(biāo)簽通過⑥的接口回傳給 QA。
2.1.7 提交 UDF 配置信息
API:/openapi/v3/udf_component/marketing/saveOrUpdateNodeConfig?token=xxx
請求體:
{
"nodeId": "節(jié)點(diǎn)ID",
"nodeName": "節(jié)點(diǎn)名稱",
"labelIdList": [
"標(biāo)簽ID1",
"標(biāo)簽ID2"
]
}
返回值:無返回值,判斷 HTTP 狀態(tài)200即可
三、UDF執(zhí)行接入文檔
系統(tǒng)流轉(zhuǎn)圖如下所示
3.1 節(jié)點(diǎn)執(zhí)行請求
為了與Quick Audience對接,您需要開發(fā)一個HTTP Server。注意是Post請求,請求超時時間為10秒。Quick Audience發(fā)起的請求和接入方回執(zhí)請求約定如下通用參數(shù),為必傳項(xiàng)。
請求URL:{UDF配置的 sendParam.batchSendUrl }
請求Header信息
Header信息讀取后需要通過java.net.URLDecoder#decode(java.lang.String, java.lang.String)
,編碼為UTF-8。
v=4 // 固定參數(shù),用于區(qū)分新老版本,新版本為4,老版本沒有這個字段
請求體:
請求入?yún)?/p> | 備注 | |||
參數(shù) | 參數(shù) | 類型 | 是否必須 | |
請求時間戳 | time | Long | 是 | |
請求ID | requstId | String | 是 | |
組件ID | componentId | String | 是 | |
組件accessKey | accessKey | String | 是 | AES密鑰長度可以為128、192或256位,對應(yīng)字符為16、24、32位。 |
消息體加密算法 | encryptionMethod | String | 否 | 默認(rèn)不加密 null 目前僅支持AES 加密,加密和填充方式為:AES/ECB/PKCS5Padding |
簽名 | signature | String | 是 | time + componentId + accessKey + accessSecret 經(jīng)過hmac 加密后 注:簽名算法和 WebHook 一樣。 |
消息體 | data | String | 是 | 經(jīng)過encryptionMethod加密后消息體:
|
請求體示例:
{
"time": 0,
"requestId": "111",
"componentId": "111",
"accessKey": "111",
"signature": "111",
"encryptionMethod": [
"AES"
],
"data": "字符串格式,詳細(xì)格式如下"
}
// data 的格式
{
"jobId": "",
"jobName": "",
"nodeId": "",
"nodeName": "",
"componentName": "",
"taskId": "",
"taskStartTimestamp": 0,
"nodeStartTimestamp": 0,
"data": {
"messageId": "",
"customerList": [
{
"customerId": "",
"labels": {},
"featureMap": {
"回執(zhí)字段":"原樣帶回"
},
"processInfo": {
"processInstanceId": "新版:旅程周期中,每個用戶的旅程實(shí)例ID",
"processInstanceStartTime": "新版:旅程周期中,每個用戶的旅程實(shí)例開始時間,時間戳格式",
"processNodeInstanceId": "新版:旅程節(jié)點(diǎn)實(shí)例ID(每次不同)",
"processNodeInstanceStartTime": "新版:旅程周期中,每個用戶的旅程的節(jié)點(diǎn)實(shí)例開始時間,時間戳格式",
"groupName":"nodeId:nodeName:groupResult(node.result),groupName(node.resultExt);nodeId:nodeName:groupResult(node.result),groupName(node.resultExt)",
"@comment":{
"groupName" : "節(jié)點(diǎn)id:節(jié)點(diǎn)名稱(界面配置的):分組結(jié)果(隨機(jī)分組的百分比數(shù)字,兩位小數(shù)):分組名稱(界面配置的);多個用分號隔開"
}
}
"@comment": {
"featureMap": "/**\n * 拓展字段,異步回執(zhí)時下游必須帶回\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 * 旅程實(shí)例ID;活動實(shí)例ID\n */",
"processInstanceName": "/**\n * 活動實(shí)例名稱(有實(shí)例的時間)\n */",
"processInstanceStartTime": "/**\n * 活動實(shí)例開始時間\n */",
"processNodeId": "/**\n * 活動節(jié)點(diǎn)ID\n */",
"processNodeName": "/**\n * 活動節(jié)點(diǎn)名稱\n */",
"processNodeInstanceId": "/**\n * 活動節(jié)點(diǎn)實(shí)例ID\n */",
"processNodeInstanceStartTime": "/**\n * 活動節(jié)點(diǎn)實(shí)例開始時間\n */",
"groupId": "/**\n * ABTest分組ID(暫未實(shí)現(xiàn),為空)\n */",
"groupName": "/**\n * ABTest分組名稱(暫未實(shí)現(xiàn),為空)\n */"
}
}
返回值:
{
"success": true,
"errorDesc": "錯誤信息",
"customerList": [
{
"messageId": "消息 ID",
"customerId": "客戶 ID",
"returnType": "回執(zhí)結(jié)果,該結(jié)果和回執(zhí)結(jié)果一樣,如果有則直接當(dāng)做回執(zhí)結(jié)果,如果不希望直接填寫回執(zhí)結(jié)果,不要傳遞",
"returnMessage": "回執(zhí)消息,長度限制255,超過會自動截取掉"
}
]
}
3.1.1 鑒權(quán)方式
簽名算法
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回執(zhí)上報
接入方執(zhí)行營銷任務(wù)后,向Quick Audience上報回執(zhí),反饋營銷消息的發(fā)送結(jié)果。
HTTP請求URL:
API:/restapi/marketing2/udfComponent/receiveCallback?
請求體:
{
"time": 0,
"componentId": "UDF組件ID",
"signature": "簽名",
"data": "加密后回執(zhí)信息,字符串",
"@comment":{
"time":"回執(zhí)時間戳,毫秒"
}
}
// data的原始格式
{
"nodeId": "節(jié)點(diǎn)ID",
"taskId": "任務(wù)ID",
"customerList": [
{
"messageId": "消息 ID",
"customerId": "客戶 ID",
"returnType": "回執(zhí)結(jié)果",
"sendTimestamp": 0,
"featureMap": {
"請求參數(shù)": "原樣回傳回來"
}
"@comment": {
"messageId": "/**\n * 消息ID,QA推送的時候 會帶上這個ID\n */",
"customerId": "/**\n * 用戶ID\n */",
"returnType": "/**\n * 回執(zhí)結(jié)果\n */",
"sendTimestamp": "/**\n * 消息推送時間\n */",
"featureMap": "發(fā)送請求時的參數(shù),需要在回執(zhí)時原樣帶回來"
},
"extParam1": "拓展參數(shù)001-自定義返回值",
"extParam2": "拓展參數(shù)002-自定義返回值",
"extParam3": "拓展參數(shù)003-自定義返回值"
}
],
"@comment": {
"nodeId": "/**\n * 節(jié)點(diǎn)ID\n */",
"taskId": "/**\n * 任務(wù)ID\n */",
"customerList": "/**\n * 回執(zhí)用戶/粉絲列表\n */"
}
}
返回值:
{
"success": true,
"errorDesc": "",
"@comment": {
"success": "/**\n * 枚舉值:true | false\n */",
"errorDesc": "/**\n * 錯誤信息描述\n */",
"data": "/**\n * 用戶信息\n */"
}
}