四,详解消息 hook 与系统对话
本章导读
在前一篇安全与签名、黑名单和权限管理、玩转聊天室和临时对话中,我们解释了一些第三方鉴权以及成员权限设置方面的问题,在这里我们会更进一步,给大家说明:
- 即时通讯的消息 Hook 机制
- 系统对话的使用方法
万能的 Hook 机制
完全开放的架构,支持强大的业务扩展能力,是即时通讯服务的特色之一,这种优势的体现就是这里将要给大家介绍的「Hook 机制」。
Hook 与即时通讯服务的关系
Hook 也可以称为「钩子」,是一种特殊的消息处理机制,与 Windows 平台下的中断机制类似,允许应用方拦截并处理即时通讯过程中的多种事件和消息,从而达到实现自定义业务逻辑的目的。
以 _messageRecieved Hook 为例,它在消息送达服务器后会被调用,在 Hook 内可以捕获消息内容、消息发送者、消息接收者等信息,这些信息均能在 Hook 内做修改并将修改后的值转交回服务器,服务器会使用修改后的消息继续完成消息投递工作。最终收消息用户收到的会是被 Hook 修改过后的消息,而不再是最初送达服务器的原始消息。Hook 也可以选择拒绝消息发送,服务器会在给客户端回复消息被 Hook 拒绝后丢弃消息不再完成后续消息处理及转发流程。
需要注意的是,默认情况下如果 Hook 调用失败,例如超时、返回状态码非 200 的结果等,服务器会忽略 Hook 的错误继续处理原始请求。如果您需要改变这个行为,可以在云服务控制台 > 即时通讯 > 设置 > 即时通讯选项 内开启 「Hook 调用失败时返回错误给客户端并放弃继续处理请求」。开启后如果 Hook 调用失败,服务器会返回错误信息给客户端告知 Hook 调用错误,并拒绝继续处理请求。
消息类 Hook
一条消息,在即时通讯的流程中,从终端用户 A 发送开始,到其他用户接收到为止,考虑到存在接收方在线/不在线的可能,会经历多个不同阶段,这里每一个阶段都会触发 Hook 函数:
- _messageReceived
消息达到服务器,群组成员已解析完成之后,发送给收件人之前调用。开发者在这里还可以修改消息内容,实时改变消息接收者的列表,以及其他类似操作。 - _messageSent
消息发送完成后调用。开发者在这里可以完成业务统计,或将消息中转备份到己方服务器,以及其他类似操作。 - _receiversOffline
消息发送完成,存在离线的收件人,在发推送给收件人之前调用。开发者在这里可以动态修改离线推送的通知内容,或通知目的设备的列表,以及其他类似操作。 - _messageUpdate
收到消息修改请求,发送修改后的消息给收件人之前调用。与新发消息一样,开发者在这里可以再次修改消息内容,实时改变消息接收者的列表,以及其他类似操作。
对话类 Hook
在对话创建和成员变动等更改性操作前后,都可以触发 Hook 函数,进行额外的处理:
- _conversationStart
创建对话,在签名校验(如果开启)之后,实际创建之前调用。开发者在这里可以为新的「对话」添加其他内部属性,或完成操作鉴权,以及其他类似操作。 - _conversationStarted
创建对话完成后调用。开发者在这里可以完成业务统计,或将对话数据中转备份 到己方服务器,以及其他类似操作。 - _conversationAdd
向对话添加成员,在签名校验(如果开启)之后,实际加入之前调用,包括主动加入和被其他用户加入两种情况。开发者可以在这里根据内部权限设置批准或驳回这一请求,以及其他类似操作。 - _conversationRemove
从对话中踢出成员,在签名校验(如果开启)之后,实际踢出之前调用,用户自己退出对话不会调用。开发者可以在这里根据内部权限设置批准或驳回这一请求,以及其他类似操作。 - _conversationAdded
用户加入对话,在加入成功后调用。 - _conversationRemoved
用户离开对话,在离开成功后调用。 - _conversationUpdate
修改对话名称、自定义属性,设置或取消对话消息提醒,在实际修改之前调用。开发者在这里可以为新的「对话」添加其他内部属性,或完成操作鉴权,以及其他类似操作。
客户端上下线 Hook
在客户端上线和下线的时候,可以触发 Hook 函数:
- _clientOnline
客户端上线,客户端登录成功后调用。 - _clientOffline
客户端下线,客户端登出成功或意外下线后调用。
开发者可以利用这两个 Hook 函数,结合 LeanCache 来完成一组客户端实时状态查询的 endpoint,具体可以参考文档《即时通讯中的在线状态查询》。
Hook 与云引擎的关系
因为 Hook 发生在即时通讯的在线处理环节,而即时通讯服务端每秒钟需要处理的消息和对话事件数量远超大家的想象,出于性能考虑,我们要求开发者使用云引擎来实现 Hook 函数。
即时通讯的云引擎 Hook 要求云引擎部署在云引擎的 生产环境,测试环境仅用于开发者手动调用测试。由于缓存的原因,首次部署的云引擎 Hook 需要至多三分钟来正式生效,后续修改会实时生效。
Hook API 细节与使用场景详解
与 conversation
相关的 hook 可以在应用签名之外增加额外的权限判断,控制对话是否允许被建立、某些用户是否允许被加入对话等。你可以用这一 hook 实现黑名单功能。
_messageReceived
这个 hook 发生在消息到达云端之后。如果是群组消息,我们会解析出所有消息收件人。
你可以通过返回参数控制消息是否需要被丢弃,删除个别收件人,还可以修改消息内容,例如过滤应用中的敏感词。返回空对象(response.success({})
)则会执行系统默认的流程。
请注意,在这个 hook 的代码实现的任何分支上 请确保最终会调用 response.success
返回结果,使得消息可以尽快投递给收件人。这个 hook 将 阻塞发送流程