Skip to content

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 示例:

1
2
3
4
5
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 请求。