77 KiB
title | weight | type |
---|---|---|
客户端-服务器 API | 10 | docs |
{{< boxes/warning >}} 本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 Forgejo 存储库 打开 Issue、提交 Pull Request 或邮件联系我们提出改进建议和参与翻译与核对。 {{< /boxes/warning >}}
客户端-服务器 API 允许客户端发送消息、控制房间以及同步会话历史。该 API 既支持不存储状态、按需从服务器延迟加载数据的轻量级客户端,也支持维护完整本地持久状态副本的重量级客户端。
API 标准
Matrix 中客户端与服务器通信的强制性基线是通过 HTTP API 交换 JSON 对象。未来可以指定更高效的传输方式,作为可选扩展。
建议使用 HTTPS 进行通信。除测试环境外,不推荐使用明文 HTTP。
客户端通过不透明的 access_token
字符串进行认证(详见 客户端认证)。
除下述例外,所有 POST
和 PUT
端点均要求客户端在请求体中提供(可能为空的)JSON 对象。对于所有带有 JSON 请求体的请求,客户端应在请求头中带上 Content-Type: application/json
,但这不是强制要求。
例外包括:
POST /_matrix/media/v3/upload
与PUT /_matrix/media/v3/upload/{serverName}/{mediaId}
,两者的请求体为上传的媒体内容。POST /_matrix/client/v3/logout
以及POST /_matrix/client/v3/logout/all
,请求体为空。
同理,所有端点都要求服务器返回一个 JSON 对象,除非对 内容仓库模块 中媒体下载端点返回的 200 响应。服务器必须为所有 JSON 响应添加 Content-Type: application/json
响应头。
所有请求和响应中的 JSON 数据必须使用 UTF-8 编码。
参见附录中的 Matrix API 规范约定 以及下文 Web 浏览器客户端 对服务器响应的附加要求。
标准错误响应
Matrix API 层发生的任何错误必须返回“标准错误响应”。格式如下:
{
"errcode": "<error code>",
"error": "<error message>"
}
error
字符串为易读的错误消息,通常是一句简要说明出错原因的语句。
errcode
是唯一字符串,可用于处理错误信息,例如 M_FORBIDDEN
。错误码的命名空间应全部大写,后接一个下划线 _
。例如自定义命名空间 com.mydomain.here
和代码 FORBIDDEN
,错误码应为 COM.MYDOMAIN.HERE_FORBIDDEN
。本规范定义的错误码以 M_
开头。
某些 errcode
定义了附加的键应在错误响应对象中出现,但 error
和 errcode
键必须始终存在。
一般建议通过错误码而不是 HTTP 状态码来表达错误。当遇到 M_UNKNOWN
错误码时,客户端应优先参考 HTTP 状态码,作为更可靠的问题指示。例如,若客户端收到 M_NOT_FOUND
错误码但请求返回 400 Bad Request,则应按资源未找到处理该错误。然而,若客户端收到 M_UNKNOWN
错误码和 400 Bad Request,应认为请求无效。
常见错误码
这些错误码可以被任意 API 端点返回:
M_FORBIDDEN
禁止访问,例如无权限加入房间、登录失败。
M_UNKNOWN_TOKEN
指定的访问令牌或刷新令牌未被识别。
若 HTTP 401 响应返回时包含额外参数 soft_logout
,详见 软登出说明。
M_MISSING_TOKEN
请求未指定访问令牌。
M_USER_LOCKED
账户已被锁定,暂时无法使用。
M_USER_SUSPENDED
账户已被停用,目前仅可执行有限操作。
M_BAD_JSON
请求包含合法的 JSON,但某种方式上格式不正确,例如缺少必需键、键值无效等。
M_NOT_JSON
请求未包含有效的 JSON。
M_NOT_FOUND
请求未找到资源。
M_LIMIT_EXCEEDED
短时间内请求过多。请等待一段时间后重试。参见 速率限制。
M_UNRECOGNIZED
服务器无法理解请求。若端点未实现,建议返回 404;端点已实现但使用了错误 HTTP 方法,应返回 405。
M_UNKNOWN
发生未知错误。
其他错误码
下列错误码专用于特定端点。
M_UNAUTHORIZED
请求未正确验证,通常由于登录失败。
M_USER_DEACTIVATED
请求关联的用户 ID 已停用。通常见于验证身份的端点,诸如 /login
。
M_USER_IN_USE
尝试注册已被占用的用户 ID 时遇到。
M_INVALID_USERNAME
尝试注册非法用户 ID 时遇到。
M_ROOM_IN_USE
createRoom
API 提供的房间别名已被占用时返回。
M_INVALID_ROOM_STATE
createRoom
API 提供的初始状态无效时返回。
M_THREEPID_IN_USE
API 提供的 threepid 已被另一账号使用,无法再次使用。
M_THREEPID_NOT_FOUND
API 提供的 threepid 未找到记录,无法使用。
M_THREEPID_AUTH_FAILED
无法对第三方标识符执行认证。
M_THREEPID_DENIED
服务器不允许使用该第三方标识符。例如服务器只允许特定域名的邮箱。
M_SERVER_NOT_TRUSTED
客户端请求用到的第三方服务器(如身份服务器)不被当前服务器信任。
M_UNSUPPORTED_ROOM_VERSION
客户端请求创建房间时使用了服务器不支持的房间版本。
M_INCOMPATIBLE_ROOM_VERSION
客户端尝试加入服务器不支持版本的房间。请检查错误响应中的 room_version
属性以获取房间版本。
M_BAD_STATE
无法执行请求的状态变更,例如尝试解禁未被禁言的用户。
M_GUEST_ACCESS_FORBIDDEN
房间或资源不允许访客访问。
M_CAPTCHA_NEEDED
完成请求需要验证码。
M_CAPTCHA_INVALID
提供的验证码与预期不符。
M_MISSING_PARAM
请求缺少必需参数。
M_INVALID_PARAM
请求参数值类型错误。例如,服务器期望整数却收到字符串。
M_TOO_LARGE
请求或实体体积过大。
M_EXCLUSIVE
请求的资源被应用服务保留,或发起请求的应用服务未创建该资源。
M_RESOURCE_LIMIT_EXCEEDED
由于主服务器资源限制,无法完成请求。例如,在共享主机环境的主服务器使用了过多内存或磁盘空间。错误必须包含 admin_contact
字段为用户提供联系方式。通常该错误会出现在尝试修改状态的路由(如发送消息、账户数据)而不是只读路由上(如 /sync
,/user/{userId}/account_data/{type}
等)。
M_CANNOT_LEAVE_SERVER_NOTICE_ROOM
用户无法拒绝加入服务器通知房间的邀请。详见 服务器通知 模块。
M_THREEPID_MEDIUM_NOT_SUPPORTED
主服务器不支持添加指定 medium 的第三方标识符。
M_THREEPID_IN_USE
客户端指定的第三方标识符不可接受,因为已被使用。
速率限制
主服务器应当实现速率限制以降低被过载风险。当请求因速率限制被拒绝时,应返回标准错误响应格式如下:
{
"errcode": "M_LIMIT_EXCEEDED",
"error": "string",
"retry_after_ms": integer (可选,已弃用)
}
主服务器应为所有 429 状态码的响应包含 Retry-After
响应头。
retry_after_ms
属性可告知客户端需等待多少毫秒后再试。该属性已弃用,应优先采用 Retry-After
响应头。
{{% changed-in v="1.10" %}}:retry_after_ms
属性已弃用,请使用 Retry-After
响应头。
事务标识符
客户端-服务器 API 通常使用 HTTP PUT
,在 HTTP 路径中带上传递由客户端生成的事务标识符(Transaction ID)。
事务 ID 的目的在于帮助主服务器区分新请求与前次请求的重发,实现请求幂等性。
事务 ID 仅用于此目的。
请求完成后,客户端应更换下一次请求的 {txnId}
。具体生成方式由实现自定,推荐使用 version 4 UUID 或当前时间戳与单调递增整数的拼接。
主服务器应当认定若事务 ID 与以前请求一致且 HTTP 请求路径一致,则为重发。
识别为重发时,主服务器应返回与原始请求相同的 HTTP 响应码和内容。例如 PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}
会以 200 OK 和原始请求响应体中的 event_id
返回。
事务 ID 的作用范围仅限于单一设备和单一 HTTP 端点。换言之,同一设备可以用相同的事务 ID 向 PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}
和 PUT /_matrix/client/v3/sendToDevice/{eventType}/{txnId}
请求,两者被视为互不相关端点。同样地,客户端在两次登录之间,用相同的事务 ID 进行两次请求也算不同请求(除非登录时指定了已存在的 device_id
)。但如果在刷新访问令牌后,对同一端点重复使用事务 ID,则视为重复请求并予以忽略。参见 访问令牌与设备的关系。
部分 API 端点允许或要求使用无需事务 ID 的 POST
请求。可选情况下,强烈建议使用 PUT
。
{{% boxes/rationale %}}
v1.7
之前,事务 ID 的作用范围为“客户端会话”,而非设备。
{{% /boxes/rationale %}}
Web 浏览器客户端
实际情况会有部分客户端以 web 浏览器或类似环境运行。此时主服务器应当响应预检请求,并在所有请求上提供跨域资源共享(CORS)头部。
服务器必须预期客户端将向其发送 OPTIONS
请求,以便客户端获取 CORS 头。本规范中的所有端点均支持 OPTIONS
方法,但服务器收到 OPTIONS
请求时不得执行端点定义的任何业务逻辑。
当客户端访问服务器发起请求,服务器应返回该路由的 CORS 头。推荐所有请求返回的 CORS 头为:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization
{{% boxes/note %}}
{{% added-in v="1.13" %}} Access-Control-Allow-Methods
响应头的推荐值仅覆盖规范现有端点。服务器如支持额外端点或方法,应相应添加。
此章节将在端点新增方法时同步更新。未来可能支持的如 PATCH
和 HEAD
。
{{% /boxes/note %}}
服务器发现
为便于用户无需明确指定主服务器 URL 或其它参数即可连接到 Matrix 服务器,客户端应在登录时通过自动发现机制根据用户的 Matrix ID 确定服务器 URL。
本节下列术语含义如下:
PROMPT
以适合当前客户端用户体验的方式从用户获取特定信息(客户端如有合适交互能力),如无法良好交互则可选择放弃。
IGNORE
停止当前自动发现机制。如无可用自动发现机制,则客户端可用其它方式获取所需参数(如提示用户或使用默认值)。
FAIL_PROMPT
提示用户自动发现因数据无效/为空而失败,并要求提供相应参数。
FAIL_ERROR
通知用户自动发现未返回可用 URL,当前登录流程终止,此时已获取合法数据但无服务器可用,不应再尝试其他可能性,用户需自主决定下一步。
Well-known URI
{{% boxes/note %}}
托管 .well-known
JSON 文件的服务器应提供 CORS 头,参见 CORS。
{{% /boxes/note %}}
.well-known
方法指在预定位置提供 JSON 文件以指定参数值。流程如下:
- 按 服务器名 规则,从用户 Matrix ID 截取第一个冒号后片段。
- 按 语法 从服务器名提取主机名。
- 以 GET 请求
https://hostname/.well-known/matrix/client
。- 返回状态码 404 时处理为
IGNORE
。 - 状态码非 200 或响应体为空,处理为
FAIL_PROMPT
。 - 解析响应体为 JSON 对象,如失败则
FAIL_PROMPT
。 - 从
m.homeserver
属性提取base_url
,该值作为主服务器基础 URL。未提供则FAIL_PROMPT
。 - 验证主服务器基础 URL:
- 按 URL 解析,如错误则
FAIL_ERROR
。 - 客户端应连接
/_matrix/client/versions
端点,确保无错误并验证响应符合预期格式。如任一步失败,处理为FAIL_ERROR
。这步仅用于排除配置错误,确认地址有效。 - 注意
base_url
可能带/
结尾,调用方需兼容两种。
- 按 URL 解析,如错误则
- 若存在
m.identity_server
,从中提取base_url
用作身份服务器基础 URL。其验证与上面主服务器 URL 验证一致,连接端点为/_matrix/identity/v2
。如果m.identity_server
存在但无base_url
,则FAIL_PROMPT
。
- 返回状态码 404 时处理为
{{% http-api spec="client-server" api="wellknown" %}}
{{% http-api spec="client-server" api="versions" %}}
{{% http-api spec="client-server" api="support" %}}
客户端认证
多数 API 端点要求用户通过访问令牌(access token)认证身份。访问令牌通常通过 登录 或 注册 流程获得,令牌可能失效;可用刷新令牌重新生成。
{{% boxes/note %}} 本规范不强制规定访问令牌格式。客户端应将其视为不透明字节序列。服务器可自由选择合适的格式。服务器实现者可参考macaroons。 {{% /boxes/note %}}
使用访问令牌
可通过请求头及 Authentication Bearer 方案提供访问令牌:Authorization: Bearer TheTokenHere
。
也可通过查询字符串参数 access_token=TheTokenHere
提供,但因易被日志泄露,已弃用,客户端不应使用。
主服务器必须同时支持两种方式。
{{% boxes/note %}} {{% changed-in v="1.11" %}} 以查询字符串方式传递访问令牌现已弃用。 {{% /boxes/note %}}
如缺少或非法凭据,请求返回 401 状态及错误码,分别为 M_MISSING_TOKEN
或 M_UNKNOWN_TOKEN
。注意,M_UNKNOWN_TOKEN
可能有以下四种情况:
当客户端收到 M_UNKNOWN_TOKEN
错误码,应:
- 如有刷新令牌,尝试刷新令牌;
- 若响应中
soft_logout
为true
,可提示用户重新登录并保留客户端已持久化的信息; - 否则,视为用户已登出。
访问令牌与设备关系
客户端设备与访问令牌及刷新令牌密切相关。Matrix 服务器应记录每个访问令牌与刷新令牌所绑定设备,以保证请求正确处理。用刷新令牌生成新访问/刷新令牌时,新一对令牌归属于原刷新令牌关联设备。
默认情况下,登录与注册流程会自动生成新 device_id
。客户端也可自定义 device_id
或(用户不变时)复用设备,并在请求体中带上 device_id
;若客户端传入 device_id
,服务器会使该设备此前的访问及刷新令牌失效。
刷新访问令牌
{{% added-in v="1.3" %}}
访问令牌可能在一定时限后过期。使用过期令牌发起 HTTP 调用会返回 M_UNKNOWN_TOKEN
错误码,且建议带有 soft_logout: true
。客户端收到此错误且持有刷新令牌应调用 /refresh
刷新令牌。即使尚未过期也可主动刷新。刷新成功后应使用新令牌发起后续请求,并可用新令牌重试先前失败请求。返回新刷新令牌时,旧刷新令牌即失效,后续刷新需用新令牌。
旧刷新令牌在新访问/刷新令牌使用前仍有效,之后即被吊销,确保客户端若未取到或保存新令牌还能重复刷新。
若令牌刷新失败且错误响应带有 soft_logout: true
,可视为软登出,尝试重新登录获取新访问令牌。否则,客户端应视为用户已登出。
不支持刷新令牌的客户端行为由主服务器决定;客户端通过在 /login
与 /register
请求体声明 refresh_token: true
表明支持刷新令牌。例如主服务器可允许使用永不过期的访问令牌,或依赖客户端软登出行为。
软登出
若服务器要求重新认证但不希望立即失效当前客户端会话,可通过在 M_UNKNOWN_TOKEN
错误响应中包含 soft_logout: true
标志进行软登出;soft_logout
默认为 false
。若 soft_logout
被省略或为 false
,则服务器已销毁会话,客户端不得重复利用;任何客户端持久信息如加密密钥和设备信息等须丢弃。若 soft_logout
为 true
,客户端可复用持久状态。
{{% changed-in v="1.3" %}} 客户端收到软登出可优先刷新访问令牌(如有刷新令牌)。如无刷新令牌或刷新失败且为软登出,可借登录 API 指定已有设备 ID 获取新访问令牌。
{{% changed-in v="1.12" %}} 若响应同时携带 M_USER_LOCKED
错误码,则直到账户解锁前无法获取新的访问令牌。
用户交互式认证 API
总览
部分 API 端点需互动式认证(User-Interactive Authentication)。主服务器可提供多种认证方式,如用户名密码、单点登录(SSO)等。本规范不限制主服务器背后授权方式,仅定义标准接口以使任意客户端可登录任何主服务器。
认证过程由一系列“阶段”组成,每个阶段客户端向服务器提交一组认证数据并等待响应,响应可能为最终成功或要求下一阶段,交互继续至最终成功。
服务器为端点提供一种或多种“流”供客户端完成认证,每种流由一组有序阶段组成。客户端可自由选择认证流,但阶段必须依次完成。未按规定流程完成应返回 401。如所有阶段完成,认证即告完成,API 调用正常返回。
REST API 中的用户交互式认证
如本文档所述 REST API,认证流程由客户端与服务器之间交换 JSON 字典实现。服务器通过 401 响应体说明所需认证数据,客户端将其置于请求参数 auth
中提交。
客户端首次请求勿带 auth
参数。主服务器返回 401 状态码及如下 JSON 体:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"flows": [
{
"stages": [ "example.type.foo", "example.type.bar" ]
},
{
"stages": [ "example.type.foo", "example.type.baz" ]
}
],
"params": {
"example.type.baz": {
"example_key": "foobar"
}
},
"session": "xxxxxx"
}
flows
外,该对象包含:
params
: 提供客户端使用所列认证类型所需补充信息。例如某认证类型作为键存储于此字典。举例 OAuth 客户端 ID 可放此信息。session
: 服务器颁发的会话标识符,客户后续认证时需返回。
客户端选定流并尝试完成首个阶段。向服务器重复发送原请求,新增 auth
字段,内容为类型名(type),会话标识符(session),以及类型相关的其它认证信息。例如阶段类型为 example.type.foo
时:
POST /_matrix/client/v3/endpoint HTTP/1.1
Content-Type: application/json
{
"a_request_parameter": "something",
"another_request_parameter": "something else",
"auth": {
"type": "example.type.foo",
"session": "xxxxxx",
"example_credential": "verypoorsharedsecret"
}
}
如服务器认证成功但仍需更多阶段,则返回 401、响应结构与首次 401 相同,另加 completed
列表指示已完成的认证类型:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"completed": [ "example.type.foo" ],
"flows": [
{
"stages": [ "example.type.foo", "example.type.bar" ]
},
{
"stages": [ "example.type.foo", "example.type.baz" ]
}
],
"params": {
"example.type.baz": {
"example_key": "foobar"
}
},
"session": "xxxxxx"
}
如某阶段需多次请求才能完成,则响应同未认证,仅追加认证类型自定义内容。
若服务器认为当前阶段尝试失败,并允许重试,则返回同上,只是多了标准错误字段 errcode
和 error
。例如:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"errcode": "M_FORBIDDEN",
"error": "Invalid password",
"completed": [ "example.type.foo" ],
"flows": [
{
"stages": [ "example.type.foo", "example.type.bar" ]
},
{
"stages": [ "example.type.foo", "example.type.baz" ]
}
],
"params": {
"example.type.baz": {
"example_key": "foobar"
}
},
"session": "xxxxxx"
}
如请求失败原因为认证以外的其他原因,则依标准格式返回错误消息。例如:
HTTP/1.1 400 Bad request
Content-Type: application/json
{
"errcode": "M_EXAMPLE_ERROR",
"error": "Something was wrong"
}
如已完成某流程全部阶段,主服务器执行业务正常返回。已完成的阶段无法重试,服务器必须返回 401 响应及已完成阶段,或如阶段都已完成则返回业务结果。
某些认证类型可由 Matrix 客户端以外方式完成,例如邮箱确认可通过点击邮件链接。此时,客户端带 session 会话重试,服务器响应与正常认证一致,依类型是否在‘completed’数组确定阶段是否完成。
{{% boxes/note %}}
使用交互式认证的端点,任何无认证数据的请求均不会成功。服务器如允许无认证完成请求应提供仅含 m.login.dummy
的阶段,但必须对无认证请求返回 401。
{{% /boxes/note %}}
示例
一个包含三阶段认证流的 API 调用流程如下:
_______________________
| Stage 0 |
| No auth |
| ___________________ |
| |_Request_1_________| | <-- 返回“session”键以供后续认证。
|_______________________|
|
|
_________V_____________
| Stage 1 |
| type: "<auth type1>" |
| ___________________ |
| |_Request_1_________| |
|_______________________|
|
|
_________V_____________
| Stage 2 |
| type: "<auth type2>" |
| ___________________ |
| |_Request_1_________| |
| ___________________ |
| |_Request_2_________| |
| ___________________ |
| |_Request_3_________| |
|_______________________|
|
|
_________V_____________
| Stage 3 |
| type: "<auth type3>" |
| ___________________ |
| |_Request_1_________| | <-- 正常返回 API 结果
|_______________________|
认证类型
本规范定义以下认证类型:
m.login.password
m.login.recaptcha
m.login.sso
m.login.email.identity
m.login.msisdn
m.login.dummy
m.login.registration_token
基于密码
类型 | 描述 |
---|---|
m.login.password |
客户端提交标识符和明文密码。 |
用此方式时,auth
内容如下:
{
"type": "m.login.password",
"identifier": {
...
},
"password": "<password>",
"session": "<session ID>"
}
identifier
属性为用户标识对象,详见 标识符类型。
如用 Matrix ID 登录:
{
"type": "m.login.password",
"identifier": {
"type": "m.id.user",
"user": "<user_id 或用户本地名>"
},
"password": "<password>",
"session": "<session ID>"
}
也可用 /account/3pid
绑定的 3PID 替代 user
:
{
"type": "m.login.password",
"identifier": {
"type": "m.id.thirdparty",
"medium": "<第三方标识符 medium>",
"address": "<用户 third-party 地址>"
},
"password": "<password>",
"session": "<session ID>"
}
如主服务器不识别所提供的 3PID,应响应 403 Forbidden。
Google ReCaptcha
类型 | 描述 |
---|---|
m.login.recaptcha |
用户完成 Google ReCaptcha 2.0 验证。 |
用法如下:
{
"type": "m.login.recaptcha",
"response": "<captcha response>",
"session": "<session ID>"
}
单点登录(SSO)
类型 | 描述 |
---|---|
m.login.sso |
通过外部单点登录提供商认证。 |
客户端用 SSO 完成认证时应采用 Fallback 机制,详见交互式认证中的 SSO。
基于邮箱(身份/主服务器)
类型 | 描述 |
---|---|
m.login.email.identity |
通过身份服务器(或支持的主服务器)认证邮箱。 |
用前需在身份服务器(或主服务器)完成邮箱认证。认证后需将 session 信息提交给主服务器。
示例:
{
"type": "m.login.email.identity",
"threepid_creds": {
"sid": "<身份服务器 session id>",
"client_secret": "<身份服务器客户端密钥>",
"id_server": "<认证身份服务器地址,例如 'matrix.org:8090'>",
"id_access_token": "<以前注册身份服务器的 access token>"
},
"session": "<session ID>"
}
如 /requestToken
时未包含 id_server
等,可省略该字段。
基于手机号/MSISDN(身份/主服务器)
类型 | 描述 |
---|---|
m.login.msisdn |
通过身份服务器(或主服务器)认证手机号。 |
用前需在身份服务器(或主服务器)完成手机号认证,后续将 session 信息提交主服务器。
示例:
{
"type": "m.login.msisdn",
"threepid_creds": {
"sid": "<身份服务器 session id>",
"client_secret": "<身份服务器客户端密钥>",
"id_server": "<认证身份服务器地址,例如 'matrix.org:8090'>",
"id_access_token": "<以前注册身份服务器的 access token>"
},
"session": "<session ID>"
}
如 /requestToken
无 id_server
,可省略该字段。
Dummy 认证
类型 | 描述 |
---|---|
m.login.dummy |
Dummy 认证始终成功且无需额外参数。 |
Dummy 认证允许服务器无需任何用户交互即可完成请求,也可区分流程(例如存在子集包含关系的两个认证流,可用 Dummy 区分)。用时仅需传 type、session:
{
"type": "m.login.dummy",
"session": "<session ID>"
}
令牌注册
{{% added-in v="1.2" %}}
类型 | 描述 |
---|---|
m.login.registration_token |
用预共享令牌认证注册账号。 |
{{% boxes/note %}}
m.login.registration_token
仅适用于 /register
端点。
{{% /boxes/note %}}
此类型允许主服务器仅向有限用户开放注册(非完全开放/关闭),需带最大长度 64 的不透明标识符(参见 Opaque Identifier)。服务器可任意定义令牌数量与有效期,如:限定 100 次、2 小时等,过期作废。
用法如下:
{
"type": "m.login.registration_token",
"token": "fBVFdqVE",
"session": "<session ID>"
}
如需确认令牌有效性可用下面的 /validity
API,但此 API 不保障使用时令牌一定有效。
{{% http-api spec="client-server" api="registration_tokens" %}}
注册时服务条款
{{% added-in v="1.11" %}}
类型 | 描述 |
---|---|
m.login.terms |
用户需接受服务条款、隐私政策等政策性文档。 |
{{% boxes/note %}}
m.login.terms
仅适用于 /register
端点。
{{% /boxes/note %}}
主服务器要求新用户接受服务条款等政策性文件。文档可能有多类型、多版本、多语言。
服务器需通过 /register
返回 401,并在 flows
中包含 m.login.terms
,params
内有结构见下文。
客户端遇到无效参数应终止注册并提示用户错误。
客户端应为每个政策提供勾选框及跳转链接,用户接受后提交仅含 type、session 的 auth
字段:
{
"type": "m.login.terms",
"session": "<session ID>"
}
服务器应记录注册过程展现的文档版本。
示例
-
客户端注册请求为:
POST /_matrix/client/v3/register
{ "username": "cheeky_monkey", "password": "ilovebananas" }
-
服务器要求接受条款,返回:
HTTP/1.1 401 Unauthorized Content-Type: application/json
{ "flows": [ { "stages": [ "m.login.terms" ] } ], "params": { "m.login.terms": { "policies": { "terms_of_service": { "version": "1.2", "en": { "name": "Terms of Service", "url": "https://example.org/somewhere/terms-1.2-en.html" }, "fr": { "name": "Conditions d'utilisation", "url": "https://example.org/somewhere/terms-1.2-fr.html" } } } } }, "session": "kasgjaelkgj" }
-
客户端将文档列表展现给用户并提示接受。
-
用户确认全部接受后,客户端重复注册请求:
POST /_matrix/client/v3/register
{ "username": "cheeky_monkey", "password": "ilovebananas", "auth": { "type": "m.login.terms", "session": "kasgjaelkgj" } }
-
所有认证步骤均已完成,请求成功:
HTTP/1.1 200 OK Content-Type: application/json
{ "access_token": "abc123", "device_id": "GHTYAJCE", "user_id": "@cheeky_monkey:matrix.org" }
{{% definition path="api/client-server/definitions/m.login.terms_params" %}}
Fallback
客户端无法预期支持所有认证类型。如遇不识别的认证类型可引导用户于浏览器打开备用页面,完成此阶段。URL 格式:
/_matrix/client/v3/auth/<auth type>/fallback/web?session=<session ID>
其中 auth type
为类型名,session ID
为会话标识。
回调页面必须返回 HTML,可以完成该认证并用如下 JS 通知客户端:
if (window.onAuthDone) {
window.onAuthDone();
} else if (window.opener && window.opener.postMessage) {
window.opener.postMessage("authDone", "*");
}
这样客户端可在内嵌浏览器用 onAuthDone
回调,或用 HTML5 跨文档消息 API。
收到通知后客户端应以仅含 session ID 的 auth
字段重发请求:
{
"session": "<session ID>"
}
示例
网页客户端可用如下 JS 打开处理未知认证类型的弹窗:
/**
* 参数:
* homeserverUrl: 主服务器基础地址 (如 "https://matrix.org")
* apiEndpoint: 正在使用的 API 端点 (如 "/_matrix/client/v3/account/password")
* loginType: 正在认证的类型 (如 "m.login.recaptcha")
* sessionID: 主服务器颁发的会话标识符
* onComplete: 认证完成的回调,参数为请求响应内容
*/
function unknownLoginType(homeserverUrl, apiEndpoint, loginType, sessionID, onComplete) {
var popupWindow;
var eventListener = function(ev) {
// 检查消息和来源
if (ev.data !== "authDone" || ev.origin !== homeserverUrl) {
return;
}
// 关闭弹窗
popupWindow.close();
window.removeEventListener("message", eventListener);
// 重发请求
var requestBody = {
auth: {
session: sessionID,
},
};
request({
method:'POST', url:apiEndpoint, json:requestBody,
}, onComplete);
};
window.addEventListener("message", eventListener);
var url = homeserverUrl +
"/_matrix/client/v3/auth/" +
encodeURIComponent(loginType) +
"/fallback/web?session=" +
encodeURIComponent(sessionID);
popupWindow = window.open(url);
}
标识符类型
部分认证方式通过用户标识符对象(identifier)标识用户。用户标识对象含 type
字段指明类型,根据类型含有不同的必需字段。
本规范定义如下标识符类型:
m.id.user
m.id.thirdparty
m.id.phone
Matrix 用户 ID
类型 | 描述 |
---|---|
m.id.user |
以 Matrix ID 标识用户。 |
通过 Matrix ID 标识用户,既可以是全限定 ID,也可以是本地用户名。
"identifier": {
"type": "m.id.user",
"user": "<user_id 或本地用户名>"
}
第三方 ID
类型 | 描述 |
---|---|
m.id.thirdparty |
以规范化第三方标识符标识用户。 |
通过 3PID 标识用户,3PID 绑定见 /account/3pid
,medium 列表见 3PID 类型。
"identifier": {
"type": "m.id.thirdparty",
"medium": "<第三方标识符类型>",
"address": "<用户第三方标识符地址>"
}
手机号
类型 | 描述 |
---|---|
m.id.phone |
以手机号标识用户。 |
以绑定手机号标识用户,手机号可由用户原样输入,由主服务器规范化。如需客户端自规范,可用 m.id.thirdparty
类型并设置 medium: msisdn
。
"identifier": {
"type": "m.id.phone",
"country": "<手机号归属国家>",
"phone": "<手机号>"
}
country
是两位大写 ISO-3166-1 alpha-2 国家码,phone
按该区域拨号规范解析。
登录
客户端可用 /login
API 获取访问令牌。
该端点 当前不 使用 用户交互式认证 API。
用户名/密码登录示例:
{
"type": "m.login.password",
"identifier": {
"type": "m.id.user",
"user": "<user_id 或本地用户名>"
},
"password": "<password>"
}
也可用 /account/3pid
绑定的 3PID:
{
"type": "m.login.password",
"identifier": {
"medium": "<第三方标识符类型>",
"address": "<用户规范化的第三方标识符地址>"
},
"password": "<password>"
}
主服务器不识别 3PID 时返回 403 Forbidden。
用登录令牌登录的方法如下:
{
"type": "m.login.token",
"token": "<login token>"
}
token
必须编码用户 ID(因请求中无其它身份信息)。如令牌无效,则返回 403 Forbidden 和错误码 M_FORBIDDEN
。
若主服务器声明支持 m.login.sso
流,且客户端支持,客户端应重定向用户至 通过 SSO 客户端登录 的 /redirect
端点。认证完成后,需要匹配 m.login.token
类型发送 /login
请求。
{{% added-in v="1.7" %}} 已认证客户端如主服务器支持可通过 POST /login/get_token
为自己账户生成一次性登录令牌。
{{% http-api spec="client-server" api="login" %}}
{{% http-api spec="client-server" api="login_token" %}}
{{% http-api spec="client-server" api="refresh" %}}
{{% http-api spec="client-server" api="logout" %}}
应用服务登录
{{% added-in v="1.2" %}}
应用服务可通过提供有效的应用服务令牌及其命名空间下的用户进行登录。
{{% boxes/note %}} 应用服务不一定需要以单独用户身份登录,可通过 身份断言 用应用服务令牌操作。但如需针对用户的令牌,可用下面 API。 {{% /boxes/note %}}
该请求需通过应用服务 as_token认证(详见客户端认证令牌用法)。
使用方式如下:
{
"type": "m.login.application_service",
"identifier": {
"type": "m.id.user",
"user": "<user_id 或本地用户名>"
}
}
如访问令牌无效、不属于应用服务,或该用户未注册,则主服务器返回错误码 M_FORBIDDEN
。
如 token 属于应用服务但用户 ID 不在其命名空间,返回错误码 M_EXCLUSIVE
。
登录 Fallback
客户端若无法识别登录流程,可用以下 fallback 登录 API:
GET /_matrix/static/client/login/
该端点返回含 JS 的 HTML 页面,可完整执行登录流程。登录成功后页面会调用 window.matrixLogin.onLogin(response)
,参数为 POST /_matrix/client/v3/login
的 JSON 响应体解析所得的 JS 对象。
{{% added-in v="1.1" %}} 可将非认证参数作为查询字符串提供至本端点,会在登录流程转发至实际登录 API。例如:
GET /_matrix/static/client/login/?device_id=GHTYAJCE
账户注册与管理
{{% http-api spec="client-server" api="registration" %}}
密码管理注意事项
{{% boxes/warning %}}
客户端应强制密码的足够复杂性,建议至少包含小写字母、大写字母、数字和符号,最少 8 位。服务器可拒绝弱密码,并返回 M_WEAK_PASSWORD
错误码。
{{% /boxes/warning %}}
账户锁定
{{% added-in v="1.12" %}}
服务器管理员可对帐号加锁(如出于安全原因),锁定行为非破坏性,可后续解锁。下述定义了客户端与服务器的行为,具体加锁/解锁方式为实现细节。
账户锁定时,服务器必须对除下列 API 外的所有客户端-服务器 API 返回 401 错误、错误码 M_USER_LOCKED
并设置 soft_logout
:
服务器可在 error
字段告知锁定原因。
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"errcode": "M_USER_LOCKED",
"error": "本账户已被锁定",
"soft_logout": true
}
服务器不应在账户锁定时立即吊销访问令牌,除非客户端主动调用上述登出端点。这样可以确保账户解锁后用户无需重新登录。
收到 M_USER_LOCKED
错误时,客户端应保留会话加密等信息,并提示用户帐户已被锁定。锁定期间应隐藏正常 UI 禁止使用账户,但应以限流方式持续轮询 /sync
等接口以检测解锁。
如需申诉可使用服务器联系方式发现。
账户停用
{{% added-in v="1.13" %}}
服务器管理员可停用用户账户以防止进一步操作。其效果类似锁定,但不会导致客户端丢失会话状态。停用可逆,不同于注销账号。
可用操作范围为服务器实现细节,但建议至少允许:
- 登录、新建会话(即使也处于停用态)
- 查看和接收消息,特别是通过
/sync
与/messages
- 验证其它设备与写交叉签名数据
- 上传密钥备份
- 离开房间与拒绝邀请
- 撤回自己发送的消息
- 注销或删除自己任意设备
- 停用账户,可设置延时防止频繁新注册
- 添加或更改管理员联系信息,但不允许移除(建议服务器记录变更日志)
一般请求如 /send/{eventType}
可根据请求参数决定是否允许,如允许发送撤回事件但不允许普通消息。
如房间用作管理员与被停用用户沟通通道,建议允许用户在该房间中发言。不想让其接收通知的管理员可考虑锁定账户。
其它被禁止的建议操作:
- 加入或敲门进入房间
- 接受或发送邀请
- 向房间发送消息
- 修改资料
- 撤回他人消息(如房间权限允许)
如客户端试图在停用时操作,服务器必须以 403 Forbidden、错误码 M_USER_SUSPENDED
响应:
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
"errcode": "M_USER_SUSPENDED",
"error": "您在账号停用期间无法执行此操作。"
}
有关停用/取消停用 API 暂未纳入本规范,属实现细节。
添加账户管理员联系信息
主服务器可独立保存一些用于管理的联系信息。此信息独立于身份服务器,可以绑定至身份服务器。
{{% boxes/note %}} 本节涉及“添加”“绑定”概念。添加(或移除)指未绑定至身份服务器的标识符;绑定(或解绑)指服务端绑定于身份服务器。取决于上下文,标识符可同时添加和绑定。 {{% /boxes/note %}}
{{% http-api spec="client-server" api="administrative_contact" %}}
当前账户信息
{{% http-api spec="client-server" api="whoami" %}}
关于身份服务器的说明
Matrix 身份服务器存储用户第三方标识符(如邮箱、手机)与用户 ID 的绑定。用户确定身份服务器后,所有客户端都应使用该身份服务器。
客户端可通过账户数据事件 m.identity_server
得知用户所选身份服务器(见本章下文)。客户端应在检测到该数据(已/未出现)前不要请求身份服务器,如有 base_url
字段则使用该身份服务器,否则用默认值,且不应在为用户设置身份服务器前将默认值写入账户数据。
客户端应监听 m.identity_server
事件变更,并同步其使用的身份服务器。
如客户端允许用户设置身份服务器,必须更新 m.identity_server
。base_url
为 null
时应视为不希望启用身份服务器,相关功能禁用。
客户端不应为缺少该事件的用户迁移补默认身份服务器,除非用户主动设置。即,用户未设置相关数据时,客户端不应主动写入默认身份服务器。
{{% event event="m.identity_server" %}}
能力协商
主服务器可能不支持部分功能,客户端需有查询主服务器能力的机制。例如主服务器采用外部认证,无法支持密码变更。
通过此机制声明的能力旨在描述 API 内可选功能,或与用户/服务器状态相关功能。不用于实验性功能,实验性或不稳定功能应由 /versions
公布。
合理能力如:
- 是否支持用户在线状态
- 是否支持可选功能如用户目录或房间目录
- 服务器对客户端速率限制、文件类型限制
不应声明为能力的有:
- 是否支持规范中处于
unstable
状态的功能 - 媒体文件大小(已由
/config
API 管理) - 可选编码/传输方式
能力以 m.
为前缀为 Matrix 规范保留,其它命名建议采用 Java 包命名风格。具体支持能力见下。
{{% http-api spec="client-server" api="capabilities" %}}
m.change_password
能力
本能力含 enabled
字段,表示用户能否调用 /account/password
API 修改密码。不出现时默认允许修改密码。出现且 enabled
为假时,客户端应提示用户无法修改密码。
示例:
{
"capabilities": {
"m.change_password": {
"enabled": false
}
}
}
m.room_versions
能力
描述服务器支持的默认及可用房间版本与稳定性级别。客户端可用以判定房间是否需升级。
示例:
{
"capabilities": {
"m.room_versions": {
"default": "1",
"available": {
"1": "stable",
"2": "stable",
"3": "unstable",
"custom-version": "unstable"
}
}
}
}
本能力参考房间版本。未被 available
标为 stable
的统统视为 unstable
。例如 future-stable
也算 unstable
。
default
为服务器新建房间采用的版本。客户端应引导有权限用户将unstable
房间升级为 default
版本。
如无本能力,客户端应以 "1"
作为默认和唯一可用稳定房间版本。
m.set_displayname
能力
本能力含 enabled
字段,标识用户能否通过资料接口修改昵称。若禁用,常为目录服务(如 LDAP)映射帐号。
此能力常与 m.set_avatar_url
成对出现。
如不出现,默认允许修改昵称。
示例:
{
"capabilities": {
"m.set_displayname": {
"enabled": false
}
}
}
m.set_avatar_url
能力
本能力唯一 enabled
字段,标识用户可否通过资料接口修改头像。典型禁用场景为外部服务(如 LDAP)账号同步。
与 m.set_displayname
能力常成对。
缺省时默认可修改头像。
示例:
{
"capabilities": {
"m.set_avatar_url": {
"enabled": false
}
}
}
m.3pid_changes
能力
本能力唯一字段 enabled
,标识用户是否能添加、删除或修改自己的三方账号。注意仅作用于管理员联系信息接口,不影响身份服务端点。禁用通常为目录服务类(如 LDAP)账号的自动同步。
缺省时默认允许修改。
示例:
{
"capabilities": {
"m.3pid_changes": {
"enabled": false
}
}
}
m.get_login_token
能力
本能力唯一字段 enabled
,标识用户是否可通过 POST /login/get_token
生成一次性登陆令牌,用于免认证客户端登陆。
缺省时,客户端应认为用户不能生成此类令牌。
示例:
{
"capabilities": {
"m.get_login_token": {
"enabled": false
}
}
}
过滤
过滤器可在服务器端创建,作为参数传递到支持事件返回的 API 里,这会影响 API 返回的数据内容。只有部分 API 支持过滤器。
房间成员延迟加载
成员事件数量巨大时占用资源较大。为节省资源,客户端可启用“延迟加载”,服务器仅发送与客户端相关的成员事件。
延迟加载作为优化不是绝对精确的,服务器可以为简化实现而多发部分事件,但应尽量减少冗余。
在过滤器层面,通过设定
RoomEventFilter
的 lazy_load_members
开启延迟加载。启用后,支持该特性的端点仅返回事件发送方的成员事件。例如带延迟加载的 /sync
仅返回时间线内发生事件相关的发送者成员事件。
处理事件序列(如循环调用 /sync
或分页 /messages
)时,事件块发送用户可能重叠。服务器可以假设客户端会保留已接收成员事件,对没变化的用户成员事件不必重发(称为“冗余成员事件”)。客户端如需总是收到全部冗余成员事件,可设 include_redundant_members
为 true。
推荐用法如下:
- 客户端初次同步
/sync
启用延迟加载,仅获取当前事件的发送人成员事件。 - 如需展示房间成员列表,可调用
/members
,参数?at
设为/sync
的 from token。房间成员列表随后跟随增量/sync
维护。 - 不支持成员补全可通过查询房间状态或
/profile
按需获取。
支持延迟加载的端点有:
API 端点
{{% http-api spec="client-server" api="filter" %}}
事件
客户端-服务器 API 披露的会话历史为事件列表。服务器将最终一致的事件图(event graph)线性化为事件流(event stream):
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]
房间事件类型
房间事件分为两类:
- 状态事件:更新房间元数据(如话题、成员等),状态由事件
type
与state_key
组成唯一键,重复键的状态会被覆盖。 - 消息事件:描述房间内临时性操作,如发送消息、设置 VoIP 通话等。
规范定义了若干 m.
前缀事件(详见 Room Events)。应用可自定义事件类型,建议采用 Java 包命名规范如 com.example.myapp.event
。
{{% boxes/note %}}
事件类型不限于本规范定义,可随意采用 Java 包命名进行自定义,只要客户端可访问所用命名空间。例如 com.example.game.score
。
{{% /boxes/note %}}
房间事件格式
“联邦”层事件格式依房间使用的房间版本而定,详见 版本1 与 版本3。
但一般客户端不会直接遇到此格式,主服务器会将事件转换为如下便于客户端解析的格式。
{{% boxes/warning %}} 事件体属于不可信数据。所有 Matrix 应用须确保事件体结构/架构符合预期后再用其内容。
任何时候都不能假定事件体字段齐全且类型正确。
原因详见 MSC2801。 {{% /boxes/warning %}}
{{% definition path="api/client-server/definitions/client_event" %}}
精简(Stripped)状态
精简状态为房间的简化状态视图,助用户了解房间基本信息,仅含部分精简后的状态事件。
精简状态事件仅有 sender
、type
、state_key
、content
。
使用场景:邀请、敲门及用户可能有加入权利的房间(如 restricted
房间)。
客户端仅于无房间实际状态时应使用精简状态,有数据后弃用。如客户端带房间存档而收到房间精简状态(如被踢后看到新邀请),应以精简状态为准,直到重新进房获取最新状态。
精简状态一般包含下列事件,尽量以精简状态形式呈现:
m.room.create
m.room.name
m.room.avatar
m.room.topic
m.room.join_rules
m.room.canonical_alias
m.room.encryption
{{% boxes/note %}} 客户端应遍历精简状态,不要假设某事件必然存在。服务器亦可包含文档未列出的事件。 {{% /boxes/note %}}
{{% boxes/rationale %}} 房间名、头像、话题、别名便于用户做出加入与否。 加入规则提醒客户端为何具备加入权限,比如不同图标辅助解释。 创建事件可判定房间类型(如是否为空间等),客户端可据此在 UI 不同区域展示。 加密信息则用于图标或相关解释。 {{% /boxes/rationale %}}
{{% boxes/warning %}} 尽管精简状态由服务器生成与下发,但接收方亦可能不准确。精简状态事件未签名,有被篡改或因延迟变更未达等可能。 {{% /boxes/warning %}}
{{% event-fields event_type="stripped_state" %}}
大小限制
事件经联邦层格式、规范化 JSON 编码后,整体不得超过 65536 字节。
字段单独限制如下:
sender
不得超过用户 ID 最大长度。room_id
不得超过房间ID最大长度。state_key
最多255字节。type
最多255字节。event_id
不得超过事件ID最大长度。
部分事件类型还有其他约束,详见各事件说明。其余键仅受全局 64KiB 限制。
房间事件
{{% boxes/note %}} 本节内容尚在完善中。 {{% /boxes/note %}}
规范现有标准事件均以 m.
开头。
{{% event event="m.room.canonical_alias" %}}
{{% event event="m.room.create" %}}
{{% event event="m.room.join_rules" %}}
{{% event event="m.room.member" %}}
{{% event event="m.room.power_levels" %}}
历史性事件
部分 m.
命名空间下的事件或见于房间,但本规范暂无业务含义,如:
m.room.aliases
早期版本有详细定义。
同步
读取事件的推荐流程为:客户端首次调用 /sync
(无 since
参数),获取每间房最新消息及房间在返回时间线开头时的状态。响应含 next_batch
字段,后续以此为 since
参数获取新消息。每房间附带 prev_batch
字段,可用作 /rooms/<room_id>/messages
的 start 参数查询更早记录。
举例,/sync
返回房间事件 E2~E5,略去 E0/E1:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]
^ ^
| |
prev_batch: '1-2-3' next_batch: 'a-b-c'
客户端后续带 next_batch
做 timeout
长轮询。服务器会保持连接,及时有新事件随时返回,仅 /sync
(及已弃用的 /events
)支持该机制。
假如下一次同步返回增量事件 E6:
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]
^ ^
| |
| next_batch: 'x-y-z'
prev_batch: 'a-b-c'
通常全部新事件都会返回。若某段时间事件过多,则大部分事件会省略,仅返回最新事件,同时返回起止区间状态差量(delta),方便客户端补全,防断层。客户端如想回补,可按返回 prev_batch
查询丢失区间事件。
例,跟进一次 /sync
带 since=x-y-z
,服务器发现新事件 E7E10,但只返回 E8E10 及前置状态差量:
| gap |
| <-> |
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10]
^ ^ ^
| | |
since: 'x-y-z' | |
prev_batch: 'd-e-f' next_batch: 'u-v-w'
客户端据此以 from=x-y-z
、to=d-e-f
查询 /rooms/<room_id>/messages
补历史。
{{% boxes/warning %}} 此 API 按事件到达主服务器时间排序,部分旧 API 按事件图偏序排序,二者可能出现同事件多次返回。客户端需基于事件 ID 去重。 {{% /boxes/warning %}}
{{% boxes/note %}}
/sync
返回 state
列表与 timeline
分离。全量同步 state
为时间线开始时刻完整状态(如新房间状态只占满时间线 state
或为零)。增量同步 state
为自 since
以来至时间线起点的变更(如时间线 limited
时)。注意 state
不一定为时间线前一刻状态,客户端不应对时间线混排该列表。
{{% /boxes/note %}}
{{% boxes/rationale %}}
本规范早期让 state
表示时间线末端状态,不理想:一是事件重复,二是客户端难以还原。例如返回时间线 [M0, S1, M2],M0/M2 同一用户发,S1 为其改昵称事件;若 state
表示末端,客户端需手动倒回 S1 状态计算 M0。
{{% /boxes/rationale %}}
{{% http-api spec="client-server" api="sync" %}}
{{% http-api spec="client-server" api="old_sync" %}}
获取房间事件
房间事件读取相关 API 如下:
{{% http-api spec="client-server" api="rooms" %}}
{{% http-api spec="client-server" api="message_pagination" %}}
{{% http-api spec="client-server" api="room_event_by_timestamp" %}}
{{% http-api spec="client-server" api="room_initial_sync" %}}
向房间发送事件
{{% boxes/note %}} {{% added-in v="1.3" %}}
如事件 关联 其它事件,服务器可能做后处理。关联类型(rel_type
)决定了可用性(如用户对同一目标事件只能发送一次)。
{{% /boxes/note %}}
{{% http-api spec="client-server" api="room_state" %}}
示例
合法写法:
PUT /rooms/!roomid:domain/state/m.example.event
{ "key" : "without a state key" }
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
{ "key" : "with 'foo' as the state key" }
非法请求:
POST /rooms/!roomid:domain/state/m.example.event/
{ "key" : "cannot use POST here" }
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
{ "key" : "txnIds are not supported" }
注意区分 state key
与 txnId
:
PUT /rooms/!roomid:domain/state/m.another.example.event/11
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }
可按用户 ID 作为 state_key
存储用户相关状态:
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
{ "animal" : "cat", "reason": "fluffy" }
也可无 state_key
:
PUT /rooms/!roomid:domain/state/m.room.bgd.color
{ "color": "red", "hex": "#ff0000" }
{{% http-api spec="client-server" api="room_send" %}}
撤回(Reductions)
因事件可扩展,恶意用户/服务器或添违法内容。部分事件无法直接删除(如成员事件),因此采用撤回手段,将事件只保留协议必需字段。撤回后的事件在客户端/服务器侧皆只返回精简内容。客户端访问已被撤回事件可在 unsigned 红包 redacted_because
带原撤回事件。
具体算法见房间版本说明。事件撤回后不可恢复。远程主服务器撤回有效性判据同理。
客户端接收到 m.room.redaction
事件时,须同步调整被撤回事件内容。
{{% boxes/note %}} 撤回事件仍能影响房间状态。撤回后,状态事件表现为属性未指定(除撤回算法保护外)。如撤回的 join 事件,用户仍为已加入;如撤回话题,则话题移除而非回滚至先前。 {{% /boxes/note %}}
事件
{{% event event="m.room.redaction" %}}
客户端行为
{{% http-api spec="client-server" api="redaction" %}}
形成事件关系
{{% changed-in v="1.3" %}}
部分场景需将一个事件逻辑关联至另一个,如回复消息、编辑、提供上下文等。
关联为父子结构,任意事件可为父。父不显式列子关系,由子通过 content
内 m.relates_to
(见下)描述。可相互嵌套形成树。
{{% boxes/note %}} 子事件可指向其他子事件,形成链甚至树型结构。 {{% /boxes/note %}}
为便于服务器聚合查找,m.relates_to
必须出现在加密事件的明文部分,不能仅内嵌在密文负载中。
{{% boxes/warning %}}
加密事件内 payload
的 m.relates_to
应被忽略,只以明文副本为准(包括无副本时)。以确保客户端与服务器关于关系的处理一致。
{{% /boxes/warning %}}
不规范、非法、跨房间等关联均忽略。客户端应平等显示无效也无关联事件,可加以错误提示。
m.relates_to
格式定义如下:
{{% definition path="api/client-server/definitions/m.relates_to" %}}
关联类型
本规范描述如下关联类型:
- 富回复(注:未用
rel_type
) - 事件替换
- 事件标注(注释、reaction)
- 线程
- 引用
子事件聚合
{{% added-in v="1.3" %}}
部分关系可由服务器按 rel_type
聚合,让客户端无需单独获取所有子事件。例如可统计有多少用户用某 reaction key。
聚合详情因关联类型而异。
下述端点提供聚合:
GET /rooms/{roomId}/messages
GET /rooms/{roomId}/context/{eventId}
GET /rooms/{roomId}/event/{eventId}
GET /rooms/{roomId}/relations/{eventId}
GET /rooms/{roomId}/relations/{eventId}/{relType}
GET /rooms/{roomId}/relations/{eventId}/{relType}/{eventType}
GET /sync
限流区间POST /search
匹配 room_events- {{% added-in v="1.4" %}}
GET /rooms/{roomId}/threads
{{% boxes/warning %}} 当前状态事件不支持聚合。欢迎补充相关 MSC 以提升支持。 {{% /boxes/warning %}}
客户端应本地追加聚合。例如收到新 reaction,更新计数。若事件本地未能找到或发生变化,需自行整合。
被撤回的父事件,其子事件(如 reaction)依然存在,但被撤回的子事件与父失去关联,需要解除聚合关系。客户端本地聚合同理。
建议客户端对聚合实现本地回显,如优化用户体验。但需注意不可二次聚合。建议为尚未获取事件 ID 的发出事件也能维护聚合信息,可用事务 ID 临时识别。
{{% boxes/warning %}} 若历史可见性受限,部分事件不可见,聚合也缺失。关键信息(如投票)应充分考虑可见性。
服务器如有历史断层,聚合也会不准确。 {{% /boxes/warning %}}
关系 API
{{% added-in v="1.3" %}}
客户端可通过下述端点取父事件的子事件,如需递归聚合则需自行处理。
通过 event_type
或 rel_type
过滤条件,服务器仅返回匹配的直接/间接关联事件,所有非匹配类型的间接关联将被排除,如想获取完整线程建议客户端本地遍历而不是用 rel_type。
{{% boxes/note %}}
由于回复未使用 rel_type
,无法通过本 API 访问。
{{% /boxes/note %}}
{{% http-api spec="client-server" api="relations" %}}
房间
类型
{{% added-in v="1.2" %}}
房间可选带类型,区分功能。无类型的房间一般为会话用途。
类型有助于客户端区分功能(会话/数据型),房间类型记录于 m.room.create
的 type
字段,建房时以 creation_content
提供。
当前规范房间类型有:
类型可扩展,依 命名空间标识符。
创建
主服务器建房时会生成 m.room.create
事件,作为事件树根;并自动设置权限等其它事件,如:
m.room.power_levels
:设置用户及动作权限等m.room.join_rules
:设置加入规则
详细参见 Room Events。创建房间接口如下。
{{% http-api spec="client-server" api="create_room" %}}
房间别名
服务器可托管人类友好的房间别名(如 #name:server.name
)。
别名以主服务器域名作用域为限,服务器一般拒绝跨域维护,因此协议不提供给外部服务器发送更新的机制。但服务器必须处理其它服务器的别名解析请求。
房间不存储自身的全部别名,权限用户可通过 m.room.canonical_alias
公布别名。别名实践中常发生漂移,请客户端校验别名链接的实际房间 ID,再做分享或使用。
{{% http-api spec="client-server" api="directory" %}}
权限
{{% boxes/note %}} 本节尚在完善中。 {{% /boxes/note %}}
房间权限通过 Power Level 实现。任一操作需满足所需 power level。m.room.power_levels
以状态事件记录房间内用户、各操作所需权限,默认用户 0,房主 100。用户可提升他人 power level,但不得超过自身。权限设定跨房间,有些操作如踢人、封禁、发送状态事件都需对应值。详情见 m.room.power_levels。
建议 power level 对应含义如下:
- 0 普通用户
- 50 协管
- 100 管理员
成员关系
必须为成员才能发送、接收事件。房间成员状态:
- 无关:不可发送接收
- 敲门:请求加入,等待批准
- 邀请:已被邀请,尚未参与
- 已加入:可正常操作
- 被封禁:不可加入
例外情形:
- 拒绝邀请:发送
m.room.member
带leave
内容,前提已被邀请 - 敲门加入:
m.room.member
带knock
内容,表示意图加入 - 撤销敲门:发送
leave
相当于拒绝邀请
部分房间需先邀请才可加入,由 m.room.join_rules
控制:
public
自由加入
invite
需邀请
knock
要先敲门,若允许可由房间成员打招呼,请求准许
{{% added-in v="1.2" %}} restricted
满足指定房间成员条件或受邀请
{{% added-in v="1.3" %}} knock_restricted
结合 restricted
与 knock
,即既可凭邀请/房间条件直接加入,也可敲门
状态转换流程:
{{% diagram name="membership" alt="成员状态机示意图" %}}
{{% http-api spec="client-server" api="list_joined_rooms" %}}
加入房间
{{% http-api spec="client-server" api="inviting" %}}
{{% http-api spec="client-server" api="joining" %}}
敲门进入房间
{{% added-in v="1.1" %}} {{% changed-in v="1.3" %}}
{{% boxes/note %}}
自 v1.3
支持敲门进入 restricted 房间。
{{% /boxes/note %}}
如加入规则允许,外部用户可 /knock
敲门,成员可邀请(/invite
)或拒绝(/kick
、/ban
、设置 leave
)。用户已在房间、已邀请、被封禁不可敲门。
同意敲门需有邀请权限,拒绝需有踢/封禁权限。
主服务器收到邀请即视为敲门被接受,无需关联至原敲门事件。服务器可自动接受邀请。
{{% http-api spec="client-server" api="knocking" %}}
限制型房间
{{% added-in v="1.2" %}} {{% changed-in v="1.3" %}}
{{% boxes/note %}}
v1.3
起,knock_restricted
房可敲门,同理需房间支持。
{{% /boxes/note %}}
限制型房间 (restricted
) 在加入规则中指定 "allow conditions"。若已被邀请,规则不影响其;否则服务器判断用户是否满足任一 condition。
目前唯一可用 condition 是 m.room_membership
:满足情况即已加入指定 room_id 的成员。例如:
{
"join_rule": "restricted",
"allow": [
{
"room_id": "!other:example.org",
"type": "m.room_membership"
}
]
}
离开房间
成员可离开房间(含拒绝邀请、撤回敲门),操作完成后对应房间将不会再出现在 /sync
返回中(除非用带 include_leave
的过滤器)。
如是 invite-only 房间,用户需被重新邀请才能再入。
用户也可“忘记房间”(forget),忘记后只有重新加入/被邀请才可恢复。
可被踢出(kick),需要操作者有足够权限。被踢视同主动离开,且只有非 invite-only 房才能再次加入。
{{% http-api spec="client-server" api="leaving" %}}
{{% http-api spec="client-server" api="kicking" %}}
房间封禁
可封禁成员,操作是将 member 调为 ban
,禁止加入、收发事件,踢出本房。必须有足够 power level,接口如下:
{
"user_id": "<待封禁成员ID>",
"reason": "string: 封禁原因"
}
或直接设置 membership:
{
"membership": "ban"
}
解封需显式发送 /rooms/<room_id>/unban
。
{{% http-api spec="client-server" api="banning" %}}
列出房间
{{% http-api spec="client-server" api="list_public_rooms" %}}
用户数据
用户目录
{{% http-api spec="client-server" api="users" %}}
用户资料
{{% http-api spec="client-server" api="profile" %}}
服务器行为
主服务器必须接受以下情况下的用户资料查询:
- 与请求方共享房间的用户
- 公开房间的成员(主服务器已知)
其它情况主服务器可直接拒绝(403 + M_FORBIDDEN
)。
远程用户资料查询成功时主服务器应向远端请求。远端可拒绝联邦查询。
不存在的用户,主服务器可选返回 403 或 404,建议 403。
资料变更通知
因 display name 和 avatar 处处用到,信息修改时会自动广播变更:
- 发送 join 状态
m.room.member
事件至其所在所有房间更新 displayname / avatar_url - 发送
m.presence
含新 displayname / avatar_url / presence
主服务器应自动完成上述通知。
此外,主服务器自有用户房间成员事件应含 displayname、avatar_url 以便客户端直接展示。
模块
模块是客户端-服务器 API 的组成部分,但并非适用于所有端点。模块定义严格区分于实验扩展或可选特性。合规服务器必须支持全部模块及相关规范(如仅面向特定客户端类型,可仅支持所需模块)。合规模块的客户端必须支持其目标特性的所有模块及规范,详见特性配置文件。
特性配置文件
Matrix 支持多种客户端形态:嵌入式 IoT 至桌面客户端。并非所有设备都能实现全部功能(如无屏幕)。客户端可归入如下类型,每类包含一组必须实现的功能。必须整体实现整类配置文件所含特性。
简要表
模块 / 配置文件 | 网页端 | 移动端 | 桌面端 | 命令行 | 嵌入式 |
---|---|---|---|---|---|
内容仓库 | 必须 | 必须 | 必须 | 可选 | 可选 |
直接消息 | 必须 | 必须 | 必须 | 必须 | 可选 |
忽略用户 | 必须 | 必须 | 必须 | 可选 | 可选 |
即时消息 | 必须 | 必须 | 必须 | 必须 | 可选 |
在线状态 | 必须 | 必须 | 必须 | 必须 | 可选 |
推送通知 | 可选 | 必须 | 可选 | 可选 | 可选 |
消息回执 | 必须 | 必须 | 必须 | 必须 | 可选 |
房间历史可见性 | 必须 | 必须 | 必须 | 必须 | 可选 |
房间升级 | 必须 | 必须 | 必须 | 必须 | 可选 |
第三方邀请 | 可选 | 必须 | 可选 | 可选 | 可选 |
输入状态通知 | 必须 | 必须 | 必须 | 必须 | 可选 |
用户与房间提醒 | 必须 | 必须 | 必须 | 可选 | 可选 |
VoIP | 必须 | 必须 | 必须 | 可选 | 可选 |
客户端配置 | 可选 | 可选 | 可选 | 可选 | 可选 |
设备管理 | 可选 | 可选 | 可选 | 可选 | 可选 |
端到端加密 | 可选 | 可选 | 可选 | 可选 | 可选 |
事件注释与回应 | 可选 | 可选 | 可选 | 可选 | 可选 |
事件上下文 | 可选 | 可选 | 可选 | 可选 | 可选 |
事件替换 | 可选 | 可选 | 可选 | 可选 | 可选 |
已读未读标记 | 可选 | 可选 | 可选 | 可选 | 可选 |
访客接入 | 可选 | 可选 | 可选 | 可选 | 可选 |
内容管理策略列表 | 可选 | 可选 | 可选 | 可选 | 可选 |
OpenID | 可选 | 可选 | 可选 | 可选 | 可选 |
引用关系 | 可选 | 可选 | 可选 | 可选 | 可选 |
内容举报 | 可选 | 可选 | 可选 | 可选 | 可选 |
富回复 | 可选 | 可选 | 可选 | 可选 | 可选 |
房间预览 | 可选 | 可选 | 可选 | 可选 | 可选 |
标签功能 | 可选 | 可选 | 可选 | 可选 | 可选 |
SSO 客户端登录/认证 | 可选 | 可选 | 可选 | 可选 | 可选 |
Secrets | 可选 | 可选 | 可选 | 可选 | 可选 |
点对点消息 | 可选 | 可选 | 可选 | 可选 | 可选 |
服务器访问控制列表 | 可选 | 可选 | 可选 | 可选 | 可选 |
服务器管理 | 可选 | 可选 | 可选 | 可选 | 可选 |
服务器通知 | 可选 | 可选 | 可选 | 可选 | 可选 |
服务器端搜索 | 可选 | 可选 | 可选 | 可选 | 可选 |
空间 | 可选 | 可选 | 可选 | 可选 | 可选 |
贴纸消息 | 可选 | 可选 | 可选 | 可选 | 可选 |
第三方网络 | 可选 | 可选 | 可选 | 可选 | 可选 |
线程 | 可选 | 可选 | 可选 | 可选 | 可选 |
各模块具体需实现内容详见相应章节。
客户端种类
独立网页端(Web)
即以 Matrix 为主的 Web App,SPA、MPA 等。
移动端(Mobile)
专门为移动设备开发的 Matrix 客户端,通常为 App。
桌面端(Desktop)
原生桌面 GUI 客户端。
命令行(CLI)
文本终端使用的客户端。
嵌入式(Embedded)
嵌入至其他网站(如 iframe)或嵌入设备,如家用电器、汽车等,仅做少量操作,无需完整通信功能。
Application
指嵌入网页,供特定网站专用的 Matrix 客户端,通常为单一用途。
Device
指嵌入设备(如水壶、冰箱、汽车)的小型客户端,仅执行部分操作,环境受限。
{{% cs-module name="instant_messaging" %}} {{% cs-module name="rich_replies" %}} {{% cs-module name="voip_events" %}} {{% cs-module name="typing_notifications" %}} {{% cs-module name="receipts" %}} {{% cs-module name="read_markers" %}} {{% cs-module name="presence" %}} {{% cs-module name="content_repo" %}} {{% cs-module name="send_to_device" %}} {{% cs-module name="device_management" %}} {{% cs-module name="end_to_end_encryption" %}} {{% cs-module name="secrets" %}} {{% cs-module name="history_visibility" %}} {{% cs-module name="push" %}} {{% cs-module name="third_party_invites" %}} {{% cs-module name="search" %}} {{% cs-module name="guest_access" %}} {{% cs-module name="room_previews" %}} {{% cs-module name="tags" %}} {{% cs-module name="account_data" %}} {{% cs-module name="admin" %}} {{% cs-module name="event_context" %}} {{% cs-module name="sso_login" %}} {{% cs-module name="dm" %}} {{% cs-module name="ignore_users" %}} {{% cs-module name="stickers" %}} {{% cs-module name="report_content" %}} {{% cs-module name="third_party_networks" %}} {{% cs-module name="openid" %}} {{% cs-module name="server_acls" %}} {{% cs-module name="mentions" %}} {{% cs-module name="room_upgrades" %}} {{% cs-module name="server_notices" %}} {{% cs-module name="moderation_policies" %}} {{% cs-module name="spaces" %}} {{% cs-module name="event_replacements" %}} {{% cs-module name="event_annotations" %}} {{% cs-module name="threading" %}} {{% cs-module name="reference_relations" %}}