1. 事件推送
石墨文档中台-开发文档
  • 1. 适用范围
  • 00. 概述
    • 石墨文档中台能做什么?
    • 三种典型的业务接入场景
    • 石墨文档中台支持哪些格式?
  • 01. 快速开始
    • 基本概念
    • 场景一:10 分钟创建预览文件
    • 场景二:10 分钟创建协同编辑文件
  • 02. 鉴权与安全
    • 整体概述
    • 签名凭证 Token
    • 签名凭证 Signature
  • 03. 文件预览
    • 整体概述
    • 如何预热预览缓存
    • 如何防盗链
    • 常见问题处理
  • 04. 文件编辑
    • 整体概述
    • 协同文档权限设计
    • 协同文件保存与更新机制
    • 协同文件复制与删除
  • 05. 文件导入导出
    • 整体概述
    • 常见问题处理
  • 06. 石墨前端 API
    • 整体概述
    • 公共 API
      • 公共处理方法
      • 顶部栏定制 HeaderBars
    • 编辑器 API
      • 轻文档
      • 传统文档
      • 表格
      • 幻灯片
      • 表单
      • 应用表格
  • 07. 石墨后端 API
    • 整体概述
    • 错误码说明
    • 文件-预览 API
      • 访问预览文件
      • 创建文件预览缓存
    • 文件-协同编辑文件管理 API
      • 访问协同编辑文件
      • 创建协同文件
      • 创建协同文件副本
      • 删除协同文件
    • 文件-导入导出 API
      • 文件导入
        • 文件导入说明
        • 创建导入任务
        • 获取导入进度
        • 创建导入任务(旧版)
        • 获取导入进度(旧版)
      • 文件导出
        • 文件导出流程
        • 创建导出任务
        • 获取导出进度
    • 文件-表格文件(Excel) API
      • 表格接口参数说明
      • 获取表格内容
      • 获取表格中的评论数
      • 更新表格内容
      • 追加表格内容
      • 删除表格行
      • 新增表格工作表
    • 文件-文稿文件(Word) API
      • 文稿书签说明
      • 读取文稿书签内容
      • 替换文稿书签内容
    • 文件-文档文件(类 Markdown) API
      • 获取文档中的评论列表
    • 文件-应用表格文件(多维表格)API
      • 应用表格列及单元格值结构
      • 应用表格接口调用规则
      • 获取数据表列表
      • 创建数据表
      • 获取字段列表
      • 创建字段
      • 更新字段
      • 删除字段
      • 新增行
      • 获取单行
      • 更新行
      • 删除行
    • 文件-获取额外信息 API
      • 获取文件的纯文本内容
      • 文件纯文本字数统计
      • 获取文件的历史列表
      • 获取文件的版本列表
      • 获取文件内容中所有的 @ 人信息列表
      • 还原文件历史版本
    • 系统管理 API
      • 应用管理
        • 获取应用详情
        • 更新应用回调地址
      • 用户席位管理
        • 用户席位状态说明
        • 获取用户列表和席位状态
        • 激活用户席位​
        • 取消用户席位​
        • 批量设置用户席位
    • 其他 API
      • 上报事件
      • 创建行为历史
      • 推送文件内全部的用户
      • 推送用户全部的 websocket 连接
    • 获取行列表
  • 08. 回调接口(你的应用需实现的接口)
    • 整体概述
    • 文件信息
      • 文件权限说明
      • [重要] 获取文件元信息-协同文档
      • [重要] 获取文件元信息-预览文档
      • 获取当前用户的文件列表
      • 获取文件的协作者列表
      • 获取接入方指定文件的完整访问地址
      • 获取文件元信息-协同文档自动任务(admin)
      • 根据指定用户获取文件元信息-协同文档(admin)
    • 用户信息
      • 批量获取用户信息(admin)
      • [重要] 获取当前用户信息
      • 获取当前用户所在团队信息
      • 获取指定用户信息
      • 获取用户水印信息
      • 获取用户部门路径
      • 批量获取用户信息
    • 团队和部门
      • 特殊部门 ID 说明
      • 获取团队下的成员列表
      • 获取部门信息
      • 获取部门的下级部门节点
      • 获取部门下的成员分页列表
    • 搜索功能
      • 获取与文件相关的用户列表
      • 获取与文件相关的文件列表
      • 按关键字搜索文件和用户列表
    • 事件推送
      • 整体概述
      • 评论(Comment)
        • 轻文档
          • 添加评论
          • 删除评论
          • 结束评论
          • 对于评论的回复评论
        • 表格
          • 添加评论
          • 删除评论
          • 结束评论
          • 对于评论的回复评论
        • 传统文档
          • 对于评论的回复评论
          • 添加评论
          • 更新评论
          • 删除评论
        • 幻灯片
          • 添加评论
          • 删除评论
          • 结束评论
          • 对于评论的回复评论
        • 应用表格
          • 添加评论
          • 对于评论的回复评论
          • 删除评论
      • 讨论(Discussion)
        • 轻文档
          • 发送讨论消息
      • 提及(MentionAt @ 人)
        • 轻文档
          • 在评论中 at
          • 在讨论中 at
          • 在正文中 at
        • 表格
          • 在评论中 at
          • 在正文中 at
        • 传统文档
          • 在评论中 at
          • 在正文中 at
        • 应用表格
          • 在评论中 at
          • 在正文中 at
      • 日期提醒 (DateMention)
        • 轻文档
          • 创建
          • 修改
          • 删除
        • 表格
          • 创建
          • 修改
          • 删除
        • 传统文档
          • 创建
          • 修改
          • 删除
      • 文件内容更新 (FileContent)
        • 文件内容更新
      • 文档协作者协同状态变化 (Collaborator)
        • 文档协作者协同状态变化
      • 文件版本 (Revision)
        • 版本
      • 系统事件 (System)
        • 系统事件
      • 回调请求错误(实验性)
        • 回调请求错误
  • 09. 核心模型
    • 你的应用如何设计应用(app)模型?
    • 你的应用如何设计文件数据模型?
    • 你的应用如何设计通讯录模型?
    • 你的应用系统如何设计文件权限模型?
  • 10. 典型场景方案
    • 云盘场景
    • IM 场景
    • 示例代码仓库
  • 11. 常见问题
    • 访问接口提示 Signature
    • 文件预览或导入报错
    • 首次接入 SDK 报错
    • 文档预览如何做防盗链
    • 复制粘贴、全屏操作不正常
    • 如何实现文档模板功能
    • 文档内容何时保存
    • 移动端不支持 blob 协议导致预览失败
    • 如何实现文件重命名
    • 如何通过接口修改文档内容
    • @人员时如何直接跳转至对应锚点
  1. 事件推送

整体概述

当用户在石墨文档中创建评论、@ 人、更新文件内容、添加协作者时,石墨会通过 POST {endpoint_url}/events 把事件推送到你的应用。如果你的应用需要感知这些事件,来触发后续其他的业务流程,可以通过处理回调事件的方式来实现这个目标。
如果你的应用没有订阅石墨文档事件来触发后续业务流程处理的场景,那么可以跳过此文档。

一、如何快速对接事件推送#

先在控制台或 更新应用回调地址 把 endpointUrl 设好,所有事件统一推送到 {endpointUrl}/events。
实现一个 POST /events 路由:按 X-Shimo-Sdk-Event 头分发,不管业务处理成败都尽量返回 200 {},避免触发 10009 / 10010 错误。
处理逻辑必须幂等:石墨在网络抖动或你的应用返回非 200 时会重试,重复事件可能到达多次。
联调阶段同时监听 System 事件下的「回调请求错误」,可以在分钟级感知到自己接口出现的失败。

二、事件总览#

下表是当前所有可推送事件。X-Shimo-Sdk-Event 头取 kind(必要时附带 type)作为路由依据,载荷对象是该事件携带的业务字段所在的 JSON key。
X-Shimo-Sdk-Eventkindtypeaction 取值载荷对象触发时机
CommentCommentcommentcreate / update / delete / resolvecomment用户增加、修改、删除或结束评论
CommentCommentdiscussioncreate 等discussion用户发送讨论消息
MentionAtMentionAtmention_atcreatecomment.userIds用户在评论中 @ 了人
DateMentionDateMention—create / update / delete提醒规则用户插入、修改、删除日期提醒规则(石墨不负责到点提醒)
FileContentFileContent—updatefileContent文档内容被修改并保存成功
CollaboratorChangedCollaboratorChanged—enter / leavecollaboratorChanged用户进入或离开协同
RevisionRevision—create / update / deleterevision用户创建、修改、删除版本
SystemSystemcallback_request_error 等—request / responseSDK 系统级事件,当前以「回调请求错误」为主

三、整体推送时序#

四、请求与响应规范#

请求地址
POST {endpoint_url}/events
endpoint_url 来自应用注册时配置的回调前缀,可通过 更新应用回调地址 修改。
Header 参数
名称必填类型说明
X-Shimo-Sdk-Event是string路由依据,取值见上表
X-Shimo-Token视事件而定string石墨持有当前用户 Token 时传入,用于你的应用对本次请求鉴权
X-Shimo-Credential-Type视事件而定string石墨无法提供用户 Token 时填写,参考 Token 与回调鉴权
X-Shimo-Signature视事件而定string石墨用应用 appId / appSecret 主动签发的 JWT,用于无 Token 时的请求来源校验
Response
HTTP Code:200。任何非 200 都会被识别为失败,并触发 10009 / 10010。
Body:空 JSON {} 即可,石墨不读取响应体。
超时:默认 5 秒,超时按失败处理。

五、凭证类型#

不同事件触发源不同,到达你的应用时携带的凭证组合也不同。务必按凭证类型分别校验,不要假设 X-Shimo-Token 永远存在。
事件触发源X-Shimo-TokenX-Shimo-Credential-TypeX-Shimo-Signature校验建议
Comment / MentionAt / Revision / DateMention用户主动操作有通常省略通常省略用 Token 还原用户后再判断业务权限
FileContent / CollaboratorChanged编辑器内核 + 协同服务无3有校验 X-Shimo-Signature 来源;用户用 userId 字段定位
System 下的回调错误石墨服务端无3有同上

六、重试与去重策略#

重试节奏:失败后石墨在分钟级内做 2~3 次指数退避重试;超过重试次数后写入推送失败日志,并通过 System 事件二次通知。
去重键:石墨不保证事件只送达一次。建议在你的应用侧用业务幂等键去重;下表给出推荐键:
事件推荐幂等键备注
Commentcomment.guid + action同一评论可能经历 create → update → resolve
MentionAtcomment.guid + userIds 排序后一条评论 @ 多人时,避免重复通知
DateMentionfileId + ruleId + action规则 ID 在事件 body 内提供
FileContentfileId + fileContent.version版本号单调递增,作幂等最稳
CollaboratorChangedfileId + userId + clientId + action + timestamp多端登录时同用户的不同实例
RevisionfileId + revision.revisionId + action—
System.callback_request_errorappId + request.url + timestamp同一接口可能短时间多次失败
快入慢处理:5 秒内尽快返回 200,把 IM 推送、邮件、AI 处理等耗时业务放进消息队列异步消费。
乱序保护:事件可能乱序到达(尤其 enter 在 leave 后)。对计数器、在线集合一类的状态,应该用 timestamp 做单调比较,过期事件丢弃。

七、排查清单#

现象可能原因修复方向
控制台日志频繁出现 10009 / 10010你的应用返回非 200 / 3xx / 抛 5xx检查 /events 路由是否被前置中间件(鉴权、CSRF)拦截;返回体改成 200 {}
同一事件被重复处理你的应用偶发返回 5xx 触发石墨重试加幂等键 + 入队
收不到 FileContent 事件endpoint 没配;高频编辑被合并 / 限流;防火墙拦截看 System.callback_request_error;网关侧确认石墨出口 IP
MentionAt 触发但 IM 没推送业务侧把 Comment 也当作 @ 触发,去重逻辑误删用 comment.guid + userIds 做幂等,按 MentionAt 为唯一触发
DateMention 创建后没有按时提醒误以为石墨负责到点由你的应用维护 schedule,到点自行下发
X-Shimo-Token 缺失返回 401事件来源是石墨主动签发,没有用户 Token走 X-Shimo-Credential-Type=3 + X-Shimo-Signature 通道,不要强校验 Token
签名校验失败时钟漂移 / appSecret 不对 / 缓存了旧密钥同步 NTP;用 签名工具对照;轮换密钥后清缓存
协同人头像列表偶发漏人仅按 userId 维护在线集合,多端登录时被误删按 (userId, clientId) 二元组维护,全部 clientId 离开才视为下线

八、公共字段#

绝大多数事件都包含下面这组公共字段,载荷对象单独列在分章里。
字段类型必填含义
kindstring是事件大类,对应 X-Shimo-Sdk-Event
typestring否子类型,例如 comment / discussion / mention_at
actionstring视事件业务动作,例如 create / update / delete / enter / leave
fileIdstring是你的应用的文件 ID
userIdstring是你的应用的用户 ID;触发此事件的用户
timestampinteger是事件产生时间,毫秒级时间戳

九、事件 → 业务动作映射#

这张表给出每个事件最常见的业务侧处理,可以作为接入清单。
事件业务侧典型动作是否建议落库是否要触发用户通知
Comment同步评论到业务消息中心 / 审批流;维护未读数是视评论是否提及用户
MentionAt给被 @ 用户发 IM / 站内信 / 待办是是(唯一触发点)
Revision更新版本列表入口;写审计是仅创建时(可选)
FileContent刷新业务文件「最近修改时间 / 最近编辑人」视频率否(高频,不要触达用户)
CollaboratorChanged维护「正在编辑的人」缓存;做在线人头像视频率,可只入缓存否
DateMention同步规则到 schedule;到点由自家定时任务下发是到点时由自家系统发
System.callback_request_error接入企业 IM 告警;触发自动 oncall是是(运维侧)

十、事件详解#

更详细的事件内容见本章节子目录。

评论 Comment#

触发时机:用户在文档中增加、修改、结束(resolve)或删除一条评论。X-Shimo-Sdk-Event: Comment,凭证:用户 Token。
字段类型必填说明
comment.guidstring是评论 ID
comment.contentstring是评论文本内容
comment.userIdsstring[]是评论中被 @ 的用户;同样的信息会通过 MentionAt 再单独推送一次
comment.selectionGuidstring是划词高亮区域 ID
comment.selectionContentstring是选中的文字内容
示例:
{
  "kind": "Comment",
  "type": "comment",
  "action": "create",
  "fileId": "doc_123",
  "userId": "user_42",
  "timestamp": 1717200000000,
  "comment": {
    "guid": "cmt_abc",
    "content": "这里要不要补一句免责声明?",
    "userIds": ["user_7"],
    "selectionGuid": "sel_xyz",
    "selectionContent": "本服务不构成投资建议"
  }
}
处理建议:评论事件经常和 MentionAt 成对出现。如果你的业务系统已经监听 MentionAt 做 @ 通知,建议在 Comment 处理器里跳过 userIds,避免一条 @ 评论触发两次推送。

讨论 Discussion#

触发时机:用户发送讨论消息。Header 同 Comment,type: discussion,载荷对象 discussion。
字段类型必填说明
discussion.idstring是讨论消息 ID
discussion.unixusinteger是微秒级时间戳
discussion.contentstring是讨论文本
discussion.positionIdstring是预留字段,目前无用,请保留透传

提及 MentionAt#

触发时机:用户在评论、讨论或正文中 @ 了人。X-Shimo-Sdk-Event: MentionAt,type: mention_at,action: create,凭证:用户 Token。
载荷字段同「评论」,关键是 comment.userIds。处理建议:把这条事件作为 IM / 站内信通知的唯一触发点,幂等键 comment.guid + 排序后的 userIds。
示例:
{
  "kind": "MentionAt",
  "type": "mention_at",
  "action": "create",
  "fileId": "doc_123",
  "userId": "user_42",
  "timestamp": 1717200000000,
  "comment": {
    "guid": "cmt_abc",
    "content": "@张三 看下这段表述",
    "userIds": ["user_7"],
    "selectionGuid": "sel_xyz",
    "selectionContent": "..."
  }
}

日期提醒 DateMention#

触发时机:用户在文档中插入、修改、删除「日期 + 提醒人」规则时立即推送。X-Shimo-Sdk-Event: DateMention,action: create / update / delete,凭证:用户 Token。
说明
石墨只在规则发生变更时通知,不会在目标时间到达时再发一次。如果业务需要「到点提醒」,需要由你的应用自行落库 + 起定时任务。
处理建议:把日期提醒规则同步到你的应用的 schedule 表里,按 fileId + ruleId 做主键;删除事件到来时也同步清理。

文件内容更新 FileContent#

触发时机:文档内容被用户修改并被石墨服务器处理成功后推送。X-Shimo-Sdk-Event: FileContent,action: update。这条事件大概率以 X-Shimo-Credential-Type=3 + X-Shimo-Signature 的方式到达。
字段类型必填说明
fileContent.versioninteger是此次更新产生的新版本号
示例:
{
  "kind": "FileContent",
  "type": "FileContent",
  "action": "update",
  "fileId": "doc_123",
  "userId": "user_42",
  "timestamp": 1717200000000,
  "fileContent": { "version": 314 }
}
处理建议:这是更新业务侧「最近修改时间 / 最近编辑人」最准确的来源。高频写入文档时事件会被合并和限流,不要把它当成实时光标级别的同步;用 version 做幂等键最稳。

协作者协同状态变化 CollaboratorChanged#

触发时机:协同列表中的某个用户进入或离开。X-Shimo-Sdk-Event: CollaboratorChanged,action: enter | leave,凭证多为 Credential-Type=3 + Signature。
字段类型必填说明
collaboratorChanged.clientIdstring是协作客户端实例 ID;同一用户多端登录时每端的 clientId 不同
处理建议:用于做「正在编辑的人头像列表」时,按 (fileId, userId, clientId) 维护在线集合,不要直接按 userId 增删——一个用户多端时 leave 会先于 enter 到来,按 userId 删除会误下线。

版本 Revision#

触发时机:用户创建、修改、删除文档版本。X-Shimo-Sdk-Event: Revision,action: create | update | delete,凭证:用户 Token。
字段类型必填说明
revision.revisionIdinteger是版本号
revision.titlestring是版本标题
revision.labelstring是版本标签
revision.docHistoryIdstring是历史快照 ID
处理建议:用来同步业务侧「版本列表」入口或追加审计记录,不要当成普通编辑事件,编辑请订阅 FileContent。

系统事件 System#

X-Shimo-Sdk-Event: System,目前以「回调请求错误」(callback_request_error)为主要子类型,仍为实验性事件,未来字段可能变化。凭证:Credential-Type=3 + Signature。
回调请求错误的载荷关键字段:
字段类型必填说明
kindstring是固定为系统事件标识
typestring是错误类型,例如 callback_request_error
appIdstring是应用 ID
timestampinteger是毫秒级时间戳
request.urlstring是石墨实际请求的 URL
request.headersobject是含 X-Shimo-Token / X-Shimo-Signature
request.bodystring是请求体(字符串化)
response.statusinteger是你的应用返回的 HTTP 状态
response.headersobject是你的应用返回的响应头
response.bodystring是你的应用返回的响应体
errorMessagestring是石墨侧补充的错误说明
处理建议:把这条事件落库的同时,告警 request.url + response.status + errorMessage,能在分钟级定位到具体回调接口故障。注意:石墨明确说此事件未覆盖所有失败场景,所以你的应用仍应在自己接口侧做监控。

十一、实战代码骨架#

下面是接入 /events 的最小骨架(伪代码,未做异常处理):
app.post('/events', async (req, res) => {
  const eventName = req.headers['x-shimo-sdk-event']
  const credType = req.headers['x-shimo-credential-type']
  const token = req.headers['x-shimo-token']
  const signature = req.headers['x-shimo-signature']

  // 1. 来源校验:Token 优先,否则走签名
  let userContext
  if (token) {
    userContext = await resolveUserByToken(token)
  } else if (credType === '3' && verifySignature(signature)) {
    userContext = { system: true }
  } else {
    return res.status(401).end()
  }

  // 2. 幂等去重(按事件 → 幂等键映射)
  const idempotencyKey = buildIdempotencyKey(eventName, req.body)
  if (await seen(idempotencyKey)) return res.json({})
  await markSeen(idempotencyKey, ttlSeconds = 7 * 86400)

  // 3. 快入慢处理:入队,业务逻辑异步消费
  await eventQueue.push({ eventName, body: req.body, userContext })

  // 4. 始终返回 200,避免触发 10009 / 10010
  res.json({})
})
异步消费侧,按事件分发:
async function handleEvent({ eventName, body }) {
  switch (eventName) {
    case 'MentionAt': return notifyMentionedUsers(body.comment)
    case 'Comment':   return syncCommentToInbox(body.comment, body.action)
    case 'FileContent': return updateDocLastModified(body.fileId, body.fileContent.version)
    case 'CollaboratorChanged': return updatePresence(body)
    case 'Revision':  return appendAuditLog(body.revision, body.action)
    case 'DateMention': return upsertSchedule(body)
    case 'System':    return alertOps(body)
  }
}
修改于 2026-06-22 02:43:30
上一页
事件推送
下一页
评论(Comment)
Built with