字段名称 | 字段类型 | 字段说明 |
---|---|---|
webhook名称 | 字符串 | 标记该webhook的名称 |
消息接收地址 | 字符串 | 接收webhook的链接地址 |
鉴权方式 | 单选 | 具体配置见下文 |
发送目标ID | 单选 | 接收消息的目标id,(用户id,设备id等) |
用户属性 | 单选(字符串类型) | 参数名称: 该参数名,发送时使用,会和模板参数放在一起 |
模板参数 | 见模板参数类型表 | 参数名称: 该参数的名称,发送时使用 |
与GMP的webhook对接,您需要开发一个HTTP Server。注意是POST请求
Request Body是一个list(一次最多发送50条),结构如下,可以将多个用户的触发合并在一个请求中。对于任何类型的数据(如整数,小数,日期等类型),在发送请求时,所有的字段全部转为字符串进行处理
字段名 | 字段类型 | 字段属性 | 说明 |
---|---|---|---|
server_str | 字符串 | - | 用于问题定位,数据回传/上报,字段详情见下文 |
user_profile | Object | 发送目标ID | 对象类型,target_type的value值表示发送目标ID类型,target_id的value值表示发送目标ID值 |
params | Map<string,any> | 模板参数+用户属性 | kv类型,key字段值配置模板参数/参数名称(用户属性)时确定,value字段类型由配置模板参数和用户属性时确定 |
类型 | 写入内容 | 样式 |
---|---|---|
字符串 | 字符串 | |
文本 | 可以插入用户id,用户属性,用户标签,短链 | |
数值 | 整数 | |
小数 | 小数 | |
数组 | 支持非对象 | |
对象 | 可以多层嵌套 | |
结构体数据 | map格式,value只支持字符串或者文本,支持在任务触达配置中手动动态添加字段。 | |
日期 | 前端传当前日期 | |
日期时分秒 | 前端传当前日期时分秒 | |
图片 | 将文件上传到minio,webhook字段中存储minio的链接 | |
单选下拉选择框 | 需要配置的时候添加选项,支持文本上传配置选项 | |
多选下拉选择框 | 需要配置的时候添加选项,支持文本上传配置选项 | |
单选下拉输入框 | 需要配置的时候添加选项,支持文本上传配置选项。可以在任务配置的时候新增选项 | |
多选下拉输入框 | 需要配置的时候添加选项,支持文本上传配置选项。可以在任务配置的时候新增选项 | |
动态参数 | 仅能同时选择用户id/用户属性/用户标签 |
Webhook POST请求中的Body结构
[{ "user_profile":{ "target_type":"phoneid", "target_id":"13422145048" }, "params":{ "key":"value", "CustomizedTemplate":{ // 自定义模板部分 "CustomizedTemplateDesc":{ "applyInfo":"123", "code":"1", "content":"验证码为${code}", "createTime":"1648032613645", "id":"1", "name":"n1", "relatedAccountNum":"123", "relatedProductNum":"123", "signature":"123", "smsType":"0", "updateTime":"1648119013645" }, "CustomizedTemplateParams":{ "code":"code_val" } } }, "server_str":"{\"log_id\":\"1016485613913050009950000000000MTM0MjIxNDUwNDg=9ed53f_69184\",\"task_id\":\"2453\",\"sub_task_id\":\"11754\",\"webhook_id\":281,\"task_type\":\"task\",\"log_str\":\"MXx8MjQ1M3wxMTc1NHwxMTc1NHx0YXNrfDEzNDIyMTQ1MDQ4fHwxMzQyMjE0NTA0OHxwaG9uZWlkfHBob25laWR8MjgxfHdlYmhvb2t8\"}" }]
[{ "user_profile":{ "target_type":"web_id", "target_id":"13422145048" }, "params":{ "city": "北京", //用户属性中的city,会在gmp后台获取到对应的属性,前端页面不展示 "http": "xxx", //模板参数里面的http "CustomizedTemplate":{ // 自定义模板部分 "CustomizedTemplateDesc":{ "applyInfo":"123", "code":"1", "content":"验证码为${code}", "createTime":"1648032613645", "id":"1", "name":"n1", "relatedAccountNum":"123", "relatedProductNum":"123", "signature":"123", "smsType":"0", "updateTime":"1648119013645" }, "CustomizedTemplateParams":{ "code":"code_val", "dsce1":"xxx" } } }, "server_str":"{\"log_id\":\"1016485613913050009950000000000MTM0MjIxNDUwNDg=9ed53f_69184\",\"task_id\":\"2453\",\"sub_task_id\":\"11754\",\"webhook_id\":281,\"task_type\":\"task\",\"log_str\":\"MXx8MjQ1M3wxMTc1NHwxMTc1NHx0YXNrfDEzNDIyMTQ1MDQ4fHwxMzQyMjE0NTA0OHxwaG9uZWlkfHBob25laWR8MjgxfHdlYmhvb2t8\"}" }]
HTTP请求URL:
POST请求 http://${gmp_host}:${gmp_port}/gmp/webhook
body:
//v2.8-2.10 { "log_id": "xxxx", "log_str": "xxxx", "receipt_code": 3000, } //v2.11 { "log_id": "xxxx", "log_str": "xxxx", "receipt_code": 3000, "receipt_message": "xxxx", "extra": "xxx", "receipt_time": 1634010444, //事件发生的时间戳,秒级 "request_id": "xxxx" //每次请求唯一,该id一致当做一次请求,基于该id去重 }
字段名 | 类型 | 备注 |
---|---|---|
log_id | string | requestbody中server_str中的log_id字段,必须,否则上报失败 |
log_str | string | requestbody中server_str中的log_str字段,必须,否则上报失败 |
receipt_code | int | 返回码 |
extra | json | 需要回传的额外信息,如外呼时长等 |
receipt_message | string | 返回信息 |
receipt_time | int | 事件发生的时间戳 |
request_id | string | 客户消息id(非必填)gmp会使用logid+request_id进行去重统计实际触达量 |
receipt_code:3000 到达成功
receipt_code:3001 用户点击
receipt_code:4000 发送失败
server_str的字段(用于做回执上报):
"server_str": "{\"log_id\":\"logId1111\",\"task_id\":\"11\",\"sub_task_id\":\"0\",\"batch_id\":\"fbe352\",\"webhook_id\":\"14\",\"task_type\":\"task\",log_str:\"xxxx\"}"
server_str字段解析
字段名 | 类型 | 备注 |
---|---|---|
log_id | string | 消息唯一id,被调用方可以基于这个字段去重 |
task_id | string | 触达任务id |
sub_task_id | string | 触达子任务id,每次发送都相当于一次子任务,定时单次任务,只有一个子任务;定时重复任务,会有多个子任务;每个子任务id不同,且和任务id也不同 |
batch_id | string | 无需关注 |
webhook_id | string | webhook通道的id |
task_type | string | 任务类型,"task":表示触达任务,"canvas":表示流程画布 |
log_str | string | 回执上报数据,字段长度>64个字符 |
Response
{ "code":0, "message":"success" //数据接收成功 } { "code": 1002, //数据接收失败 "message": "request params error" //参数错误 }
v2.10版本支持
HTTP请求URL:
POST请求 http://${gmp_host}:${gmp_port}/gmp/webhookList
body:
[{ "log_id": "xxxx", "log_str": "xxxx", "receipt_code": 3000, "receipt_message": "xxxx", "extra": "xxx", "receipt_time": 1634010444, //事件发生的时间戳,秒级 "request_id": "xxxx" //每次请求唯一,该id一致当做一次请求,基于该id去重 }, { "log_id": "xxxx", "log_str": "xxxx", "receipt_code": 3000, "receipt_message": "xxxx", "extra": "xxx", "receipt_time": 1634010444, //事件发生的时间戳,秒级 "request_id": "xxxx" }, { "log_id": "xxxx", "log_str": "xxxx", "receipt_code": 3000, "receipt_message": "xxxx", "extra": "xxx", "receipt_time": 1634010444, //事件发生的时间戳,秒级 "request_id": "xxxx" }]
Response
{ "code":0, "err_data":[] //数据都接收成功 } //假设上报了三条数据,第1,3条数据上报失败,第2条成功 { "code": -1, //数据接收失败 "err_data": [ //上报失败的数据列表 { "message": "request params error", "code": 1002, //批量请求第一条数据错误 "index": 1 }, { "message": "system error", "code": 1000, //批量请求第三条数据错误 "index": 3 } ] }
由于新建Webhook通道的时候可以选择鉴权方式
signature,并将此signature通过Request Header传递过去来做鉴权,您的服务接受到请求后,同样根据Request Body(后续版本会有增加字段的可能,需要根据收到的Request Body数据计算签名,再解析数据)与webhook通道配置的密钥进行HmacSHA1算法加密,如果计算的值与从Request Header中传过来的signature相同,则可以确定是此请求是从GMP中发送的。
func HmacSHA1(secretKey string, requestBody string) string { mac := hmac.New(sha1.New, []byte(key)) mac.Write([]byte(data)) return hex.EncodeToString(mac.Sum(nil)) }
public String HmacSHA1(String secretKey,String requestBody) throws Exception { byte[] data = secretKey.getBytes("utf-8"); SecretKey sk = new SecretKeySpec(data, "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(sk); byte[] text = requestBody.getBytes("utf-8"); return Hex.encodeHexString(mac.doFinal(text)); }
需要从maven中引入依赖
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.15</version> </dependency>
Request Body
[{ "user_profile": { "target_type": "mobile", "target_id": "13333333333" }, "params": { "string": "string", "text": "用户所在的地址是北京", "datetime": "2019-08-08", "integer": "123", "decimal": "158.123", "percentage": "18.5" } }, { "user_profile": { "target_type": "mobile", "target_id": "13222222222" }, "params": { "string": "string", "text": "用户所在的地址是天津", "datetime": "2019-08-08", "integer": "123", "decimal": "158.123", "percentage": "18.5" } }]
SecretKey:123456
Sign: 5d34b7fac1a6817ff8466c09000bf886e0a0c348
先解析到结构体再做签名校验,会导致新增的参数被忽略,验签失败。
解析json数据的时候,对key做了排序,导致收到的json数据和发送的json数据里面的参数顺序不一致,导致验签失败。
json数据中,可能会包含空数据(null,{})类型,如果下游接口不理解空数据,可能会过滤掉这个参数,导致验签失败。
Request Header中获得username与password,如果获得的值与您在Webook通达中配置的一样,则可以确定是此请求是从GMP中发送
Oauth2使用的是客户端账号密码模式
参数 | 类型 | 参数含义 |
---|---|---|
ClientId | string | 客户端id,gmp的id |
Secret | string | 密钥 |
Token地址 | string | 获取token的请求地址 |
token过期时间 | int | 过期时间(秒级),token存储的时间,过了这个时间就会去重新请求token |
//post form 格式 { "client_id":"ClientId", "client_secret":"Secret", "grant_type":"client_credentials" //写死的 } //resp 返回内容 { "access_token":"123456", "token_type":"bearer" } 最终webhook发送时,token格式是"{token_type} {access_token}" // bearer 123456 在header中填入 Authorization:token //Authorization:bearer 123456
HTTP 200且有Response Body
{ "message": "success", "code": 0, "err_data":[ { "logid":"xxx", "message":"xxx", }, { "logid":"xxx", "message":"xxx", } ] }
code | message | err_data | |
---|---|---|---|
发送成功 | 0 | success | 长度为0 |
发送失败(批量发送全部失败) | 非0 | 失败原因 | 长度为0 |
批量发送部分失败 | 0 | success | 部分失败数据 |