Webhook 通知机制
UBI SDK 提供通过 Webhook 机制发布事件通知的能力。接入方需要提供如下信息给百姓车联以开通 Webhook 事件通知服务:
- endpoint:Webhook 通知的地址,一般为 https://your.hostname/notification/uri 的形式。
事件通知以 HTTP POST 请求的形式发送给 webhook endpoint,Content-Type 为 application/json,请求的 body 符合 通知机制简介 章节描述的数据格式。
消息认证
UBI SDK 平台发往 webhook endpoint 的请求会携带一个包含消息认证签名的 HTTP header,接入方的服务应当验证该签名以忽略非法请求。下面是一个 webhook 事件通知请求的 HTTP header 示例:
| POST /notification/uri HTTP/1.1
Host: your.hostname
Authorization: HMAC-SHA256 9c6f2d79f46f2d01a371ac226fb8ef4ee39e2bc3282055b3235550763dfd01ec
Content-Type: application/json
Content-Length: 798
|
Authorization 头由 HMAC-SHA256
与签名部分组成。其中签名部分为使用 HTTP request body 计算的 HMAC-SHA256 摘要的 16 进制表示,密钥为应用的 AppSecret。校验 webhook 请求签名合法性的示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class SignatureValidator {
public static String calculateSignature(String appSecret, String requestBody) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(appSecret.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] digest = sha256_HMAC.doFinal(requestBody.getBytes("UTF-8"));
return Hex.encodeHexString(digest);
}
public static void main(String[] args) throws Exception {
String appSecret = "your-app-secret";
String requestBody = "http-request-body";
String signature = "signature-extracted-from-authorization-header";
String expectedSignature = calculateSignature(appSecret, requestBody);
boolean isValid = expectedSignature.equals(signature);
System.out.printf("isValid: %s, expectedSignature: %s\n", isValid, expectedSignature);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | import hashlib, hmac
def calculate_signature(app_secret, request_body):
h = hmac.new(app_secret.encode('utf-8'), None, hashlib.sha256)
h.update(request_body.encode('utf-8'))
return h.hexdigest()
if __name__ == '__main__':
app_secret = "your-app-secret"
request_body = "http-request-body"
signature = "signature-extracted-from-authorization-header"
expected_signature = calculate_signature(app_secret, request_body)
is_valid = (signature == expected_signature)
print("is_valid: {}, expected_signature: {}".format(is_valid, expected_signature))
|
通知响应
接入方提供的 webhook endpoint 正确响应 webhook 通知时应回复 HTTP 状态码为 2xx 的响应。Webhook endpoint 应在 10 秒内响应 webhook 请求,否则 UBI SDK 会认为请求因超时失败。
重试
如果 webhook 请求因网络错误或响应不符合预期等原因而失败,UBI SDK 会在 1 分钟,5 分钟,20 分钟,60 分钟,6 小时,24 小时后重试该请求(最多重试 6 次),直到该请求被正常响应或者超过最大重试次数。
Webhook 请求可能因重试等原因被重复送达,接入方的服务需正确处理重复的 webhook 请求。