RabbitMQ URI 规范
概述
本规范定义了 "amqp" URI 模式。符合规范的 URI 代表了 AMQP 0-9-1 客户端以及某些 RabbitMQ 插件连接到 RabbitMQ 节点所需的的信息。
简介
本规范的范围仅限于 AMQP 0-9-1,这是 RabbitMQ 实现的原始协议。AMQP 0-9-1 客户端连接到 RabbitMQ 节点,以根据消息模型发布和消费消息。
客户端需要多条信息才能建立和协商 AMQP 0-9-1 连接。这些连接参数包括
建立与服务器的底层 TCP/IP 连接所需的参数(即主机地址和端口)。
用于验证客户端的信息。AMQP 0-9-1 使用 SASL 进行身份验证。通常使用
PLAIN
机制,因此身份验证参数包括用户名和密码。"虚拟主机"(或 *vhost*)的名称,该名称指定了协议引用的实体(例如交换机和队列)的命名空间。请注意,这不是 HTTP 意义上的虚拟托管。
RabbitMQ 客户端通常会从配置文件或环境变量中获取所有这些参数,以便为其设置连接。因此,如果连接参数可以组合成单个字符字符串,而不是作为不同的配置设置,将会很方便。这意味着只需要一个配置设置,并且只需要将一个值传递给客户端库。
但是,将连接参数组合成单个字符串需要一个约定,该约定由客户端库理解,用于准确描述连接参数的表示方式和分隔方式。理想情况下,应该标准化这种约定,以便它可以被多个 AMQP 0-9-1 客户端库一致地实现。这种标准的明显基础是 RFC3986 中定义的用于 URI 的通用语法。
本规范的目的是定义 "amqp" 和 "amqps" URI 模式,这些模式在通用 URI 语法中表示 AMQP 0-9-1 连接参数。
"amqp" URI 模式
AMQP 0-9-1 URI 的语法由以下 ABNF 规则定义。这些规则中未在此定义的所有名称都取自 RFC3986。
amqp_URI = "amqp://" amqp_authority [ "/" vhost ] [ "?" query ]
amqp_authority = [ amqp_userinfo "@" ] host [ ":" port ]
amqp_userinfo = username [ ":" password ]
username = *( unreserved / pct-encoded / sub-delims )
password = *( unreserved / pct-encoded / sub-delims )
vhost = segment
根据此语法成功解析 URI 后,连接参数将根据以下部分的描述确定。
主机
建立底层 TCP 连接的主机根据 RFC3986 第 3.2.2 节中的主机组件确定。请注意,根据 ABNF,主机组件不能缺失,但可以为空。
端口
建立底层 TCP 连接的端口号根据 RFC3986 中的端口组件确定。端口组件可以缺失,这由缺少 ":" 字符来将其与主机分隔表示。如果它缺失,则应改为使用 AMQP 0-9-1 的 IANA 分配端口号 5672。
用户名和密码
如果存在,用户名和密码组件应在通过 connection.secure
和 connection.secure-ok
AMQP 0-9-1 方法执行的 SASL 交换中使用。用户名和密码中的任何百分号编码的八位字节应在用于 SASL 交换之前进行解码,并且生成的八位字节序列应被视为 UTF-8 编码。
用户名和密码都可以缺失;它们的缺失由缺少 "@" 字符来将其与 amqp_userinfo 分隔表示。如果用户名存在,则密码可以缺失;这由缺少 ":" 字符来将其与用户名分隔表示。空用户名和密码与缺失的用户名和密码不等效。
RFC3986 指出 "出现在 userinfo 组件中的密码已过时,应被视为错误"(第 7.5 节)。虽然这对于面向用户的应用程序(例如 web 浏览器)以及可能以不安全的方式存储和显示的 URI 来说是合理的建议,但对于后端应用程序来说不一定有效。许多这些应用程序是 "无头" 服务,并代表整个应用程序而不是特定用户打开 RabbitMQ 连接。因此,用户名和密码识别应用程序而不是人类用户,并且很可能与出现在安全配置设置存储中的连接参数一起包含。面向用户的应用程序,它们代表特定用户建立 RabbitMQ 连接,也是可能的。在这种情况下,用户名和密码可能由用户提供以识别自己。但是,这些应用程序是例外而不是规则。因此,实现本规范的应用程序的作者不应认为自己受 RFC3986 第 7.5 节的约束。另请参阅下面的 "安全注意事项" 部分。
虚拟主机
虚拟主机 (vhost) 组件用作 connection.open
AMQP 0-9-1 方法的虚拟主机字段的基础。vhost 中的任何百分号编码的八位字节应在传递到服务器之前进行解码。
请注意
- URI 的 vhost 组件不包含路径中的开头 "/" 字符。这样就可以引用任何 vhost,而不仅仅是那些以 "/" 字符开头的 vhost。
- vhost 是一个段。因此,出现在 vhost 名称中的任何 "/" 字符必须进行百分号编码。具有多段路径的 URI 不遵守此规范。
vhost 组件可以缺失;这由缺少 amqp_authority 后面的 "/" 字符表示。缺失的 vhost 组件与空 (即零长度) vhost 名称不等效。
处理缺失组件
某些 URI 组件(端口、用户名、密码、vhost 和查询)可能从 URI 中缺失。主机不能缺失,但可以为空;为了本节的目的,将零长度主机视为缺失。
除了端口(在上面的第 2.2 节中介绍)之外,本规范没有规定实现应该如何处理缺失的组件。可能的方法包括但不限于以下方法
- 缺失的组件可以用默认值替换。
- 面向用户的应用程序可能会提示用户提供缺失组件的值。
- 缺失的组件可能会导致错误。
此外,应用程序可能对不同的组件采用不同的策略。
例如,URI "amqp://",其中所有组件都缺失,可能会导致客户端库使用一组默认值,这些默认值对应于连接到本地 RabbitMQ 服务器,并以访客用户身份进行身份验证。这对于开发目的将很方便。
"amqps" URI 模式
"amqps" URI 模式用于指示客户端建立与服务器的安全连接。
AMQP 0-9-1 规范假设底层传输层提供可靠的字节流式虚拟电路。当不需要在网络上保护流量时,通常使用 TCP/IP 连接。
在必须保护流量的情况下,可以使用 TLS(参见 RFC5246)。当前的做法只是将 AMQP 0-9-1 建立在 TLS 之上以形成 "AMQPS"(类似于 HTTPS 将 HTTP 建立在 TLS 之上的方式)。AMQP 0-9-1 不提供将非安全连接升级为安全连接的方法。因此,支持安全和非安全连接的服务器必须在不同的端口上侦听这两种类型的连接。
除了方案标识符之外,"amqps" URI 模式的语法与 "amqp" URI 模式相同。
amqps_URI = "amqps://" amqp_authority [ "/" vhost ]
amqps URI 的解释与相应的 "普通" URI 的解释在两个方面有所不同。在所有其他方面,解释是相同的。
- 客户端必须充当 TLS 客户端,并在底层 TCP/IP 连接建立后立即启动 TLS 握手。所有 AMQP 0-9-1 协议数据都作为 TLS "应用程序数据" 发送。除此之外,将遵循正常的 AMQP 0-9-1 行为。
- 如果 URI 中缺少端口号,则应使用 "amqps" 的 IANA 分配端口号 5671。
安全注意事项
如上面的第 2.3 节所述,URI 通常作为配置设置提供给应用程序。在这种情况下,如果密码无法合并到 URI 中,则它将简单地作为单独的配置设置提供。这减少了使用 URI 的好处,而没有提高安全性。因此,本规范覆盖了 RFC3986 对 userinfo 组件中密码的弃用。
开发人员可以随时使用密码组件,只要这样做不会影响安全性。尽管如此,他们应该意识到密码组件的内容可能是敏感的,并且他们应该避免泄露它(例如,完整的 URI 不应该出现在异常消息或日志记录中,这些信息可能对权限较低的人员可见)。
附录 A:示例
以下是一张示例表,显示了如何根据本规范解析 URI。这些示例中的许多示例旨在演示边缘情况,以阐明规范并为解析 URI 的代码提供测试用例。每行都显示一个 URI,以及每个组件的生成八位字节序列。这些八位字节序列用双引号括起来。空单元格表示缺失的组件,如第 3 节所述。
URI | 用户名 | 密码 | 主机 | 端口 | vhost |
---|---|---|---|---|---|
amqp://user:pass@host:10000/vhost | "user" | "pass" | "host" | 10000 | "vhost" |
amqp://user:passw%23rd@host:10000/vhost | "user" | "passw#rd" | "host" | 10000 | "vhost" |
amqp://user%61:%61pass@ho%61st:10000/v%2fhost | "usera" | "apass" | "hoast" | 10000 | "v/host" |
amqp:// | |||||
amqp://:@/ | "" | "" | "" | ||
amqp://user@ | "user" | ||||
amqp://user:pass@ | "user" | "pass" | |||
amqp://host | "host" | ||||
amqp://:10000 | 10000 | ||||
amqp:///vhost | "vhost" | ||||
amqp://host/ | "host" | "" | |||
amqp://host/%2f | "host" | "/" | |||
amqp://[::1] | "[::1]" (即 IPv6 地址 ::1) |
附录 B:查询参数
客户端可能需要额外的参数化来定义它们应该如何连接到服务器。标准的 URI 查询语法可用于向客户端提供更多信息。
查询参数可能比其他 URI 部分更具体于实现;因此,本文档不会尝试规定如何使用它们。但是,我们已经记录了官方支持的客户端如何读取 URI 查询参数。