跳转至

SDK 回调机制

BroSDK 的所有异步操作(浏览器打开/关闭、令牌刷新、数据同步等)均通过回调驱动,而非阻塞等待。本文档详细介绍回调的类型、状态码语义、完整事件码与错误码。

前置要求:必须先调用 sdk_register_result_cb() 注册全局异步结果回调,才能调用其他 SDK 接口。


回调类型

BroSDK 提供两种回调:

回调类型 注册函数 触发时机 用途
异步结果回调 sdk_register_result_cb() 所有异步操作的进度/结果通知 接收事件通知、请求响应、错误等
Cookie 存储拦截回调 sdk_register_cookies_storage_cb() 浏览器关闭后、Cookie 持久化前 对 Cookie 数据进行二次处理(加密/过滤/注入)

异步结果回调

回调函数类型

typedef void(SDK_CALL *sdk_result_cb_t)(
    int32_t     code,       /* 状态码或请求 ID */
    void       *user_data,  /* 注册时传入的用户指针(原样返回) */
    const char *data,       /* 通知数据(UTF-8 JSON) */
    size_t      len          /* data 的字节长度 */
);

回调参数说明

参数 类型 说明
code int32_t 状态码或请求 ID,用于判断通知类型(见下节"状态码语义")
user_data void * 注册时传入的用户指针,原样返回
data const char * JSON 通知体(UTF-8),生命周期仅限当次回调,不得持有
len size_t data 字节长度

状态码语义

code 按数值范围划分语义:

范围 含义 判断函数 说明
0 操作成功(OK) sdk_is_ok(code) 同步接口返回
1 异步任务已受理(DONE) sdk_is_done(code) 结果通过回调通知
100 ~ 255 警告(非致命) sdk_is_warn(code) 操作仍继续
10000 ~ 100000 事件 ID sdk_is_event(code) 标识事件类型
> 100000 请求 ID sdk_is_reqid(code) 关联异步请求响应
< 0 错误 sdk_is_error(code) 操作失败

推荐判断顺序

if      (sdk_is_reqid(code))  { /* 异步请求响应 */ }
else if (sdk_is_event(code))  { /* 事件通知     */ }
else if (sdk_is_done(code))   { /* 任务已受理   */ }
else if (sdk_is_ok(code))     { /* 操作成功     */ }
else if (sdk_is_warn(code))   { /* 警告         */ }
else if (sdk_is_error(code))  { /* 错误         */ }

回调处理示例(C)

static void on_sdk_result(int32_t code, void *user_data,
                          const char *data, size_t len) {
    if (sdk_is_reqid(code)) {
        /* 异步请求响应 */
        printf("[ReqID=%d] %.*s\n", code, (int)len, data);

    } else if (sdk_is_event(code)) {
        /* 事件通知 */
        printf("[Event=%s] %.*s\n", sdk_event_name(code), (int)len, data);

        /* 常见事件分支处理 */
        switch (code) {
            case 10111:  /* SDK 初始化成功 */
                break;
            case 10123:  /* Token 即将过期,应立即调用 sdk_token_update */
                break;
            case 10124:  /* Token 已过期,需重新获取 User Sign */
                break;
            case 20110:  /* 浏览器打开中 */
                break;
            case 20111:  /* 浏览器打开成功 */
                break;
            case 20112:  /* 浏览器打开失败 */
                break;
            case 20113:  /* 浏览器打开超时 */
                break;
            case 20140:  /* 浏览器关闭中 */
                break;
            case 20141:  /* 浏览器关闭成功 */
                break;
            case 20142:  /* 浏览器关闭失败 */
                break;
            case 20143:  /* 浏览器关闭超时 */
                break;
        }

    } else if (sdk_is_error(code)) {
        fprintf(stderr, "[Error] %s: %s\n",
                sdk_error_name(code), sdk_error_string(code));
    }
}

/* 注册(必须在 sdk_init 之前调用)*/
sdk_register_result_cb(on_sdk_result, NULL);

回调处理示例(TypeScript)

sdk.registerResultCb((code: number, data: string) => {
  if (sdk.isOk(code)) {
    // 操作成功
  } else if (sdk.isDone(code)) {
    // 异步任务已受理
  } else if (sdk.isEvent(code)) {
    console.log('事件:', sdk.eventName(code), data)

    switch (code) {
      case 10111: break // SDK 初始化成功
      case 10123: break // Token 即将过期
      case 20111: break // 浏览器打开成功
      case 20141: break // 浏览器关闭成功
    }
  } else if (sdk.isError(code)) {
    console.error('错误:', sdk.errorString(code))
  }
})

回调函数类型

typedef void(SDK_CALL *sdk_cookies_storage_cb_t)(
    const char *data,       /* [IN]  SDK 提取的 Cookie JSON 数据 */
    size_t      len,        /* [IN]  data 字节长度               */
    char      **new_data,   /* [OUT] 替换数据指针;NULL = 透传   */
    size_t     *new_len,    /* [OUT] 替换数据字节长度            */
    void       *user_data   /* [IN]  注册时传入的用户指针        */
);

两种工作模式

  • 透传模式:将 *new_dataNULL,SDK 使用原始数据持久化
  • 替换模式:通过 sdk_malloc() 分配替换数据写入 *new_data / *new_len

内存规则:替换数据 *new_data 必须通过 sdk_malloc() 分配,SDK 将自动调用 sdk_free() 释放。

SDK 输出的 Cookie 格式为 WebExtension API 兼容的 JSON 数组:

[
  {
    "domain": ".example.com",
    "expirationDate": 1700000000,
    "hostOnly": false,
    "httpOnly": true,
    "name": "session_id",
    "path": "/",
    "sameSite": "lax",
    "secure": true,
    "session": false,
    "storeId": "",
    "value": "abc123"
  }
]

拦截回调示例

/* 透传(不修改) */
static void on_cookies_passthrough(const char *data, size_t len,
                                    char **new_data, size_t *new_len,
                                    void *user_data) {
    *new_data = NULL;
    *new_len  = 0;
}

/* 替换(对 Cookie 数据进行二次加工) */
static void on_cookies_transform(const char *data, size_t len,
                                 char **new_data, size_t *new_len,
                                 void *user_data) {
    /* data 是 JSON 数组格式的 Cookie 数据 */
    size_t out_size = 0;
    char  *processed = my_process_cookies(data, len, &out_size);

    /* 替换数据必须使用 sdk_malloc 分配 */
    *new_data = (char *)sdk_malloc(out_size);
    memcpy(*new_data, processed, out_size);
    *new_len = out_size;
    free(processed);
}

sdk_register_cookies_storage_cb(on_cookies_transform, NULL);

内存管理

场景 规则
同步接口 out_data / out_len 输出 SDK 内部分配;使用完毕后必须调用 sdk_free() 释放
回调中接收的 data 指针 生命周期仅限当次回调,不得持有;如需保存请在回调内拷贝
Cookie 拦截回调的替换数据 必须通过 sdk_malloc() 分配;SDK 内部将调用 sdk_free() 释放

Windows 注意:SDK 分配的内存必须用 sdk_free() 释放,不得使用宿主的 free(),以避免跨 CRT 堆问题。


统一响应体格式

所有同步 C API 输出及 Web API 响应均遵循以下 JSON 信封格式:

{
  "reqid": 1006901415,
  "code": 0,
  "msg": "ok",
  "data": {
    "eventId": 0
  }
}
字段 类型 说明
reqid int 请求关联 ID(用于追踪异步请求)
code int 0 = 成功,< 0 = 错误
msg string 可读状态描述
data object 接口特定返回数据

完整事件码表

SDK 初始化事件(10110~)

事件 ID 名称 说明
10110 sdk-init SDK 初始化开始
10111 sdk-init-success SDK 初始化成功
10112 sdk-init-failed SDK 初始化失败

令牌相关事件(10120~)

事件 ID 名称 说明
10120 sdk-token-update 正在更新令牌
10121 sdk-token-update-success 令牌更新成功
10122 sdk-token-update-failed 令牌更新失败
10123 sdk-token-expire-warning 令牌即将过期(应立即调用 sdk_token_update
10124 sdk-token-expired 令牌已过期

浏览器打开事件(20110~)

事件 ID 名称 说明
20110 browser-open 浏览器打开中
20111 browser-open-success 浏览器打开成功
20112 browser-open-failed 浏览器打开失败
20113 browser-open-timeout 浏览器打开超时

浏览器关闭事件(20140~)

事件 ID 名称 说明
20140 browser-close 浏览器关闭中
20141 browser-close-success 浏览器关闭成功
20142 browser-close-failed 浏览器关闭失败
20143 browser-close-timeout 浏览器关闭超时

环境管理事件(20210~)

事件 ID 名称 说明
20210 browser-env-create 创建环境中
20211 browser-env-create-success 创建环境成功
20212 browser-env-create-failed 创建环境失败
20220 browser-env-update 更新环境中
20221 browser-env-update-success 更新环境成功
20222 browser-env-update-failed 更新环境失败
20230 browser-env-page 查询环境列表中
20231 browser-env-page-success 查询环境列表成功
20232 browser-env-page-failed 查询环境列表失败
20240 browser-env-destroy 销毁环境中
20241 browser-env-destroy-success 销毁环境成功
20242 browser-env-destroy-failed 销毁环境失败
20250 browser-env-info 获取环境信息中
20251 browser-env-info-success 获取环境信息成功
20252 browser-env-info-failed 获取环境信息失败
事件 ID 名称 说明
20260 browser-cookie-upload Cookie 上传中
20261 browser-cookie-upload-success Cookie 上传成功
20262 browser-cookie-upload-failed Cookie 上传失败
20265 browser-cookie-download Cookie 下载中
20266 browser-cookie-download-success Cookie 下载成功
20267 browser-cookie-download-failed Cookie 下载失败
20270 browser-storage-upload Storage 上传中
20271 browser-storage-upload-success Storage 上传成功
20272 browser-storage-upload-failed Storage 上传失败
20275 browser-storage-download Storage 下载中
20276 browser-storage-download-success Storage 下载成功
20277 browser-storage-download-failed Storage 下载失败

云端存储事件(20300~)

事件 ID 名称 说明
20300 browser-oss 云端操作
20301 browser-oss-init-success 云端存储初始化成功
20302 browser-oss-init-failed 云端存储初始化失败
20303 browser-oss-not-initialized 云端存储未初始化
20304 browser-oss-token-updated 云端 Token 已刷新
20305 browser-oss-notfound 云端对象未找到(首次使用该环境为正常现象)
20306 browser-oss-error 云端存储错误
20307 browser-oss-cache-hit 本地缓存命中(无需下载)
20308 browser-oss-download 云端下载中
20309 browser-oss-download-success 云端下载成功
20310 browser-oss-download-failed 云端下载失败
20311 browser-oss-upload 云端上传中
20312 browser-oss-upload-success 云端上传成功
20313 browser-oss-upload-failed 云端上传失败

浏览器核心事件(20400~)

事件 ID 名称 说明
20400 browser-core 浏览器核心
20401 browser-core-count 浏览器核心数量信息
20402 browser-core-notfound 浏览器核心文件未找到

完整错误码表

通用错误(-3000 ~ -3029)

code 名称 描述
0 OK 操作成功
1 DONE 异步任务已受理
101 WDIRNOTEXIST 工作目录不存在(警告)
102 WNOCORERESOURCE 核心资源不可用(警告)
103 WBRWPROCEXITED 浏览器进程意外退出(警告)
-3000 ENO 内部系统错误
-3001 EBUSY 资源忙 / 正在使用
-3002 ETIMEOUT 操作超时
-3003 EINVALID 参数或输入无效
-3004 ENOTFOUND 目标资源未找到
-3005 EALREADY 资源已存在
-3006 ENOTSUPPORTED 操作不被支持
-3007 EINTERNAL 内部故障
-3008 ENOSPACE 存储 / 空间不足
-3009 EACCESS 权限或访问被拒绝
-3010 ECONFLICT 资源冲突
-3011 ERESOURCE 资源不足
-3012 ENOTINITIALIZED SDK / 组件未初始化
-3013 EOVERFLOW 值或计数溢出
-3014 EFORMAT 数据格式无效
-3015 ECANCELED 操作被取消
-3016 ENOTIMPLEMENTED 功能未实现
-3017 EDEADLINEEXCEEDED 超出截止时间
-3018 EUNAUTHORIZED 未授权(令牌无效 / 过期)
-3019 EPORT_UNAVAILABLE 端口无效或被占用
-3020 ENOTSTARTED 系统未启动
-3021 ESVCSTARTED 服务启动失败
-3022 EREQIDOVERFLOW 请求 ID 耗尽 / 溢出
-3023 EOSS_NOCLIENT 云端存储客户端未初始化
-3024 EOSS_DOWNLOAD 云端下载失败
-3025 EOSS_UPLOAD 云端上传失败
-3026 EOSS_AUTH 云端鉴权失败
-3027 EOSS_NOTFOUND 云端对象未找到
-3028 ECOOKIE_RESTORE Cookie 恢复失败
-3029 ESTORAGE_RESTORE Storage 恢复失败

浏览器运行时错误(-3500 ~ -3511)

code 名称 描述
-3500 EINTERNAL_ERROR 系统严重内部错误
-3501 EDECRYPT 数据解密失败
-3502 EHTTP_POST HTTP POST 请求失败
-3503 EBRW_INVALIDENVID envId 无效
-3504 EBRW_PROCKILL 浏览器进程终止失败
-3505 EBRW_PROCCRE 浏览器进程创建失败
-3506 EBRW_PROCEXITED 浏览器进程意外退出
-3507 EBRW_NOTFOUND 浏览器核心文件未找到
-3508 EINTERNAL_GENAPIREQ 生成 API 请求失败
-3509 ETOKEN_INVALID 令牌无效
-3510 EOSS 云端存储操作错误
-3511 EWORKDIR_INVALID 工作目录无效

SDK API 错误(-4000 ~ -4094)

code 名称 描述
-4000 ESDKAPI SDK 后端 API 错误
-4094 EUNKNOWN 未知错误

相关文档