--- title: "Matrix 规范" type: docs weight: 10 --- {{< boxes/warning >}} 本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 {{< /boxes/warning >}} Matrix 定义了一套用于去中心化通信的开放 API,适用于在全球开放联盟服务器网络中安全地发布、持久保存和订阅数据,无单点控制。其用途包括即时消息(IM)、VoIP(语音通信)信令、物联网(IoT)通信,以及打通各类现有通信孤岛——为构建新一代开放实时通信生态系统提供基础。 如需对 Matrix 规范提出更改建议,请参见 [Matrix 规范更改提案说明](/proposals)。 ## Matrix API 规范由以下部分组成: * [客户端-服务器 API](/client-server-api) * [服务器-服务器 API](/server-server-api) * [应用服务 API](/application-service-api) * [身份服务 API](/identity-service-api) * [推送网关 API](/push-gateway-api) * [房间版本](/rooms) * [附录](/appendices) 此外,本介绍页面还包含了理解具体 API 所需的关键基础信息,包括 [总体架构](#architecture) 一节。 [Matrix API 浏览器](https://matrix.org/docs/api/) 便于浏览客户端-服务器 API。 ## Matrix API 简介 Matrix 是一套开放联盟的即时消息(IM)、VoIP 与物联网(IoT)通信开放 API,旨在创建并支撑一个新的全球实时通信生态系统。其目标是在互联网上提供一个开放、去中心化的发布/订阅层,用于安全持久化和发布/订阅 JSON 对象。本规范是对用于 Matrix 生态系统各组件互通讯的 API 持续标准化的结果。 Matrix 遵循的原则包括: - 以现实可用、Web 友好的 API(即基于 REST 的 JSON)为准则 - 保持简单明了 - 提供简洁架构,尽量减少第三方依赖 - 完全开放: - 完全开放联盟——任何人都应能参与全球 Matrix 网络 - 完全开放标准——公开记录的标准,无知识产权或专利许可负担 - 赋能终端用户 - 用户应可自主选择所用服务器和客户端 - 用户应能自主控制通信的隐私程度 - 用户应清楚了解其数据存储的位置 - 完全去中心化——无会话或网络整体的单点控制 - 汲取历史经验,避免重蹈覆辙 - 采纳 XMPP、SIP、IRC、SMTP、IMAP 及 NNTP 的优点,努力规避其缺陷 Matrix 提供的功能包括: - 支持无单点控制或失效的完全分布式聊天室的创建与管理 - 跨全球开放联盟服务器和服务,实现房间状态的最终一致且加密安全的同步 - 在房间中可发送与接收可扩展消息,支持(可选)端到端加密 - 可扩展的用户管理(邀请、加入、离开、踢出、封禁),基于权限级别的用户特权系统来实现 - 可扩展的房间状态管理(房间命名、别名、主题、封禁等) - 可扩展的用户档案管理(头像、显示名称等) - 用户账户管理(注册、登录、登出) - 使用第三方标识(3PID),如电子邮件地址、电话号码、Facebook 账号,进行认证、识别和发现 Matrix 用户 - 可信赖的身份服务器联盟,用于: - 发布用户公钥(PKI) - 将 3PID 映射为 Matrix ID Matrix 的终极目标是作为一个无处不在的消息层,实现任意数据在多用户、设备和服务间的同步——无论是即时消息、VoIP 呼叫建立,还是其他需可靠持久推送的对象,都能以互操作和联盟的方式从 A 推送到 B。 ### 需求级别 规范中所有部分涉及的关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY" 和 "OPTIONAL",应按 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 中所述理解。 根据实际情况,规范的某些完整部分可能是可选的。例如,[客户端-服务器 API 的模块](/client-server-api/#modules) 是否适用,取决于具体用例。上述关键词标明的强制级别,仅在该部分本身适用时才相关。 ### 规范更改提案 如需对 Matrix 规范提出更改建议,请参见 [Matrix 规范更改提案说明](/proposals)。 ## 架构 Matrix 定义了用于同步可扩展 JSON 对象(称为 “事件”)的 API,这些事件在兼容的客户端、服务器和服务间交换。客户端通常为消息/VoIP 应用或 IoT 设备/中心,通过 "客户端-服务器 API" 同步通信历史与其 “主服务器”。每个主服务器存储其所有客户端的通信历史与账户信息,并通过与其他主服务器及其客户端同步通信历史,将数据加入更广泛的 Matrix 生态。 客户端通常通过在虚拟 “房间” 内发送事件实现互通。房间数据会在*所有参与该房间的主服务器*之间进行复制。因此,*没有任何单个主服务器对指定房间拥有控制权或所有权*。主服务器将通信历史建模为房间的“事件图”——有向无环图(DAG),并利用 “服务器-服务器 API” 在各参与服务器间以最终一致性方式同步。不同主服务器间同步共享对话历史的过程即为“联盟”。Matrix 优先保证 CAP 定理中的可用性与分区容忍性,以牺牲一致性为代价。 例如,A 客户端向 B 客户端发送消息时,A 客户端通过客户端-服务器 API 向其主服务器(HS)执行一次 HTTP PUT,请求所需 JSON 事件。A 的主服务器将此事件附加到自己的房间事件图,并为保证完整性,在图的上下文中对消息签名。A 的主服务器随后通过服务器-服务器 API 的 HTTP PUT 将消息复制到 B 的主服务器。B 的主服务器验证请求、校验事件签名、授权事件内容,并将其加入自身的事件图。B 客户端再通过长连接 GET 请求从主服务器接收消息。 客户端间数据流动示意: ``` { Matrix 客户端 A } { Matrix 客户端 B } ^ | ^ | | 事件 | 客户端-服务器 API | 事件 | | V | V +------------------+ +------------------+ | |---------( HTTPS )--------->| | | 主服务器 | | 主服务器 | | |<--------( HTTPS )----------| | +------------------+ 服务器-服务器 API +------------------+ 历史同步 (联盟) ``` ### 用户 每个客户端关联一个用户账户,在 Matrix 中通过唯一的 “用户 ID” 标识。该 ID 以分配账户的主服务器为命名空间,格式为: @localpart:domain 详见附录中【标识符语法】(['Identifier Grammar' in the appendices](/appendices#identifier-grammar))。 ### 设备 在 Matrix 规范中,“设备”有其特定含义。作为用户,我可能会有多个设备:如桌面客户端、若干网页浏览器、Android 设备、iPhone 等。这些大致对应现实物理设备,但一个物理设备上可以有多个浏览器,或多个 Matrix 客户端应用,每一个都将被视为独立设备。 设备主要用于管理端到端加密所用的密钥(每个设备各拥有其解密密钥副本),也有助于用户管理访问权限——例如,可以撤销对特定设备的访问。 用户首次使用某客户端时,该客户端会注册为新的设备。设备存活时间可能依客户端类型而异。Web 客户端通常在登出时清除全部状态,每次登录都会创建新设备,以防加密密钥泄漏给新用户。移动客户端则可在登录会话超时后重用设备(前提是同一用户)。 设备通过 `device_id` 标识,在属于该用户的设备范围内唯一。 用户可为设备分配一个易于辨识的显示名称,以便管理其设备。 ### 事件 所有通过 Matrix 交换的数据均以“事件”形式表达。一般而言,每一次客户端操作(例如发送消息)对应恰好一个事件。每个事件都有一个 `type` 类型,用于区分不同数据。`type` 值必须全局唯一地按 Java [包命名规范](https://en.wikipedia.org/wiki/Java_package#Package_naming_conventions)命名,例如 `com.example.myapp.event`。特殊顶级命名空间 `m.` 保留为本规范定义事件类型——比如 `m.room.message` 是即时消息的事件类型。事件通常在某“房间”上下文中发送。 {{% boxes/warning %}} 事件体被视为不受信任数据。这意味着,任何使用 Matrix 的应用都必须在使用事件体内容之前,先校验其形状/模式是否符合预期。 **不能假设事件体总能完整且类型正确地包含所有预期字段。** 详见 [MSC2801](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2801-untrusted-event-data.md) 了解为何这种假设不安全。 {{% /boxes/warning %}} ### 事件图 房间中的事件存储于一个有向无环图(DAG),称为“事件图”。此图的部分顺序决定了房间内事件的相对时间顺序。图中每个事件有零个或多个“父事件”,用于指向主服务器视角下没有时间后继的前置事件。 一般情况下,事件只有一个父事件:即发送时房间中最新消息。但当多个主服务器同时发送消息时,可能竞态,导致单个事件出现多个后继,下一事件因而会有多个父节点。每个事件图都有一个无父事件的根节点。 为便于对事件进行时间顺序比较,主服务器会在每个事件上维护 `depth` 元数据字段。`depth` 是一个正整数,必须大于所有父事件的 `depth`,根事件 `depth` 应为 1。因此若一个事件在另一个之前,则其 `depth` 必然更小。 ### 房间结构 房间是用户可发送和接收事件的概念场所。事件发往房间,房间内所有有足够权限的参与者都能收到该事件。房间在内部通过唯一 “房间 ID” 标识,格式如下: !opaque_id:domain 每个房间只有一个房间 ID。虽然房间 ID 包含域名,其作用仅用于全局命名空间,房间**并不**驻留在所指明的域名上。 详见附录中【标识符语法】(['Identifier Grammar' in the appendices](/appendices#identifier-grammar))。 下图为 `m.room.message` 事件被发送到房间 `!qporfwt:matrix.org` 的示意: { @alice:matrix.org } { @bob:example.org } | ^ | | [HTTP POST] [HTTP GET] 房间ID: !qporfwt:matrix.org 房间ID: !qporfwt:matrix.org 事件类型: m.room.message 事件类型: m.room.message 内容: { JSON 对象 } 内容: { JSON 对象 } | | V | +------------------+ +------------------+ | 主服务器 | | 主服务器 | | matrix.org | | example.org | +------------------+ +------------------+ | ^ | [HTTP PUT] | | 房间ID: !qporfwt:matrix.org | | 事件类型: m.room.message | | 内容: { JSON 对象 } | `---> 指向前一条消息的指针 --------------` 出自 matrix.org 的 PKI 签名 事务层元数据 PKI 授权头 .................................... | 共享数据 | | 状态: | | 房间ID: !qporfwt:matrix.org | | 服务器: matrix.org, example.org | | 成员: | | - @alice:matrix.org | | - @bob:example.org | | 消息: | | - @alice:matrix.org | | 内容: { JSON 对象 } | |....................................| 联盟会在每个房间各参与主服务器之间维护*共享数据结构*。数据分为 `消息事件` 和 `状态事件`。 消息事件: 这些事件描述房间中的短暂“一次性”活动,例如即时消息、VoIP 呼叫建立、文件传输等,主要代表通信行为。 状态事件: 描述与房间有关的持久信息(状态)更新,如房间名称、主题、成员、参与服务器等。状态以房间内每个 `state_key` 和事件类型构成的键值对查找表建模。每个状态事件都会更新特定键值的内容。 房间在某一时刻的状态由事件图上一切前置事件和当前事件共同推导。如果事件间的状态描述冲突,会应用合并算法。状态解析算法具有传递性,与服务器状态无关,必须保证无论服务器为何或事件接收顺序如何,都能选出一致的事件。事件由来源服务器签名,签名内容包括父关系、类型、深度和负载哈希,并作为联盟消息推送到房间内其他服务器,目前采用全互联拓扑。服务器间还可拉取事件回填。 {{% boxes/note %}} 事件类型不限于本规范定义。开发者可随时创建新或自定义事件类型,采用 Java 包命名规范。例如,`com.example.game.score` 事件即可被客户端发送,其他客户端若有权限即可接收,前提是拥有 `com.example` 命名空间的访问权。 {{% /boxes/note %}} #### 房间别名 每个房间还可有多个“房间别名”,格式如下: #room_alias:domain 详见附录中【标识符语法】(['Identifier Grammar' in the appendices](/appendices#identifier-grammar))。 房间别名“指向”某个房间 ID,是对外宣传和发现房间时用的可读标签。要得知别名指向的房间 ID,需访问所指明域名。注意,房间别名映射至房间 ID 的关系不是固定的,随时可能切换至其他房间 ID。鉴于此,客户端*应*在首次解析别名时获取房间 ID,并在后续请求中直接使用房间 ID。 解析房间别名时,服务器还会返回参与房间、可用于加入的服务器列表。 HTTP GET #matrix:example.org !aaabaa:matrix.org | ^ | | _______V____________________|____ | example.org | | 映射: | | #matrix >> !aaabaa:matrix.org | | #golf >> !wfeiofh:sport.com | | #bike >> !4rguxf:matrix.org | |________________________________| ### 身份 Matrix 用户以 Matrix 用户 ID 唯一标识。但也支持使用现有第三方身份命名空间。Matrix“身份”描述用户的用户 ID 及其与账户*关联*的所有第三方标识(3PID)。Matrix 用户可将电子邮箱、社交账号、电话号码等 3PID 关联到其用户 ID。关联 3PID 便在 3PID 与用户 ID 之间建立映射,进而方便用户根据 3PID 搜索联系人对应的用户 ID。为确保 3PID 到用户 ID 的映射真实可靠,Matrix 采用全球联盟的可信“身份服务器”(IS)来验证 3PID、持久存储并复制映射关系。 客户端不强制接入 IS 即可接入 Matrix 生态;但如果没有 IS 将无法通过 3PID 查询用户 ID。 ### 用户档案 用户可公开与账户关联的任意键值对数据——如显示名称、头像 URL、联系邮箱、电话、网站等。 ### 用户私人数据 用户也可在账户中存储任意私有键值对数据——比如客户端偏好设置,或尚无专用 API 的服务器配置。此 API 与用户档案管理对称。 ## 通用概念 多项通用概念适用于所有 Matrix API,在此统一说明。 ### 命名空间 命名空间用于防止多应用及规范自身产生冲突。规范中用 `m.` 前缀表明该字段受规范控制。实际使用时,凡非规范字段,都*必须*遵循 Java 包命名惯例,防止冲突。 如,规范定义的事件类型都以 `m.` 前缀命名,但客户端也可发送诸如 `com.example.game.score` 的自定义事件类型(前提客户端有该命名空间权利),无需将事件纳入 `m.` 命名空间。 ### 时间戳 除非另有说明,时间戳为自 UNIX 纪元(1970-01-01 00:00:00 UTC)以来的毫秒数,不计闰秒,即每天精确为 86,400,000 毫秒。 这导致在闰秒期间,时间戳可能重复。多数编程语言本地支持此格式,例如 [ECMAScript](https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-time-values-and-time-range)。规范中,可用 POSIX、[Unix](https://en.wikipedia.org/wiki/Unix_time) 或“毫秒时间”等表述。 ## 规范版本 Matrix 作为整体以单一规范号 `vX.Y` 发布。 * `X` 的变动表示有破坏性或重大结构性更改。具体何时递增由规范核心团队决定,或如移除 JSON、变更签名算法,或当累积足够多的 `Y` 级更动时,提升大版本。 * `Y` 的变动表示向后兼容,或“可控”向后兼容的变动,通常表现为功能补充。 此外,规范版本后可加 `-` 跟随任意元数据,如 `v1.1-alpha`。对此无强制性规范,主要用于规范预发布版本。 注意,`v1.2` 设计上与 `v1.1` 向后兼容,但日后版本不保证一定与 `v1.1` 完全兼容。例如,若 `/test` 于 `v1.1` 引入、`v1.2` 弃用,则可于 `v1.3` 移除。详见下面的[弃用政策](#deprecation-policy)。 ### 接口版本化 所有 API 接口均单独版本化。例如,`/v3/sync` 被废弃时可用 `/v4/sync` 替代,并不影响 `/v3/profile`。服务器支持 `/v4/sync` 时,仍照常提供 `/v3/profile`。 MSC 若提议给某接口带来破坏性变更,亦应同时废弃现有接口。部分场景下,这可通过引入新版本接口(如 `/v4/sync` 替代 `/v3/sync`)隐式完成,复杂场景则需要 MSC 明确声明接口弃用。 ### 弃用政策 MSC 负责将规范中某项内容从稳定(默认)状态过渡为弃用。某项内容弃用足够长时间(常见为 1 个版本)后,可经由后续 MSC 从规范中彻底移除。 Matrix 实现需实现规范中的弃用功能。但一旦相关功能自规范移除,实现可自行放弃支持(如其不对外声明支持含弃用功能的版本)。例如,若 `/test` 在 `v1.2` 弃用、`v1.3` 移除,则希望声明支持 `v1.2` 的实现必须实现 `/test`,即便其同时支持 `v1.3`。若实现*仅*声明支持 `v1.3`,则无需实现 `/test`。 ### 传统版本化 新版本系统推行前,Matrix 的各 API 单独版本化。新规范版本模式下不再适用。 历史上,API 版本号为 `rX.Y.Z`,其中 X 约等于重大变更、Y 为向后兼容更新,Z 为补丁或微小调整。 现行全局版本从 `v1.1` 起。 [Matrix 1.0](https://matrix.org/blog/2019/06/11/introducing-matrix-1-0-and-the-matrix-org-foundation/) 并未直接与某规范版本对应,而对应各 API 的如下版本: | API/规范 | 版本 | |--------------------------|------------| | 客户端-服务器 API | r0.5.0 | | 服务器-服务器 API | r0.1.2 | | 应用服务 API | r0.1.1 | | 身份服务 API | r0.2.0 | | 推送网关 API | r0.1.0 | | 房间版本 | 1, 2, 3, 4, 5 | `v1.0` **不得** 由服务器在 [`GET /_matrix/client/versions`](/client-server-api/#get_matrixclientversions) 响应中返回。 ## 许可协议 Matrix 规范遵循 [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 授权。