# 主题重写

很多物联网设备不支持重新配置或升级,如果需要修改设备业务行为的主题,会非常困难。

EMQX 的主题重写功能可以帮助使这种业务升级更容易:通过给EMQX一套规则,它可以改变订阅、发布等业务操作的主题名称。

EMQX 的保留消息延迟发布可以与主题重写结合使用。例如,当用户想使用延迟发布时,他们可以使用主题重写来将消息重定向到所需的主题。

注意

由于发布/订阅授权检查会在主题重写之前执行,所以只要确保重写之前的主题能够通过 ACL 检查即可。

# 配置主题重写规则

EMQX 的主题重写规则需要用户自行配置,用户可以自行添加多条主题重写规则,规则的数量没有限制,但由于任何携带主题的 MQTT 报文都需要匹配一遍重写规则,因此此功能在高吞吐场景下带来的性能损耗与规则数量是成正比的,用户需要谨慎地使用此功能。

每条主题重写规则的格式如下:

rewrite = [
  {
    action:       "all"
    source_topic: "x/#"
    dest_topic:   "x/y/z/$1"
    re:           "^x/y/(.+)$"
  }
]
1
2
3
4
5
6
7
8

每个重写规则由过滤器、正则表达式和目标表达式组成。

重写规则分为 publishsubscribeall 规则,publish 规则匹配 PUBLISH 报文携带的主题,subscribe 规则匹配 SUBSCRIBE、UNSUBSCRIBE 报文携带的主题。all 规则对 PUBLISH、SUBSCRIBE 和 UNSUBSCRIBE 报文携带的主题都生效。

在启用主题重写的前提下,当收到 MQTT 数据包(如带有主题的PUBLISH消息)时,EMQX 将使用数据包中的主题来依次匹配配置文件中规则的主题过滤器部分。匹配成功之后,正则表达式就会被用来提取主题中的信息,然后用目标表达式替换旧的主题,生成一个新的主题。

目标表达式可以使用 $N 格式的变量来匹配从正则表达式中提取的元素。$N 的值是指从正则表达式中提取的第 N 个元素,例如,$1 是正则表达式提取的第一个元素。

同时,表达式中也可以使用 ${clientid} 代表 客户端Id, 使用 ${username} 代表 客户端用户名

应该注意的是,EMQX 是以配置文件中的重写规则顺序。当一个主题可以同时匹配多个主题重写规则的主题过滤器时,EMQX 仅使用第一个匹配的规则来重写该主题。

如果规则中的正则表达式与 MQTT 数据包的主题不匹配,则重写失败,其他规则将不会被用来重写。因此,需要仔细设计 MQTT 数据包主题和主题重写规则。

# 示例

假设 etc/emqx.conf 文件中已经添加了以下主题重写规则:

rewrite = [
  {
    action:       "all"
    source_topic: "y/+/z/#"
    dest_topic:   "y/z/$2"
    re:           "^y/(.+)/z/(.+)$"
  }
  {
    action:       "all"
    source_topic: "x/#"
    dest_topic:   "z/y/x/$1"
    re:           "^x/y/(.+)$"
  }
  {
    action:       "all"
    source_topic: "x/y/+"
    dest_topic:   "z/y/$1"
    re:           "^x/y/(\d+)$"
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

如果订阅五个主题。 y/a/z/b, y/def, x/1/2, x/y/2, 和 x/y/z

  • y/def 不符合任何主题过滤器,所以它不执行主题重写,只是订阅 y/def 主题。
  • y/a/z/b 匹配 y/+/z/# 主题过滤器,EMQX 执行第一条规则,并通过正则表达式匹配元素 [a、b] ,将匹配的第二个元素带入 y/z/$2 ,并实际订阅主题 y/z/b
  • x/1/2 匹配 x/# 主题过滤器,EMQX 执行第二个规则。它不通过正则表达式匹配元素,不执行主题重写,并实际订阅了 x/1/2 的主题。
  • x/y/2 同时匹配 x/#x/y/+ 两个主题过滤器,EMQX 以相反的顺序读取配置,所以它优先匹配第三个。通过正则替换,它实际上订阅了 z/y/2 主题。
  • x/y/z 同时匹配 x/#x/y/+ 两个主题过滤器,EMQX 以相反的顺序读取配置,所以优先级匹配第三个。该元素没有通过正则表达式进行匹配,没有进行主题重写,它实际上订阅了 x/y/z 主题。需要注意的是,即使第三条的正则表达式匹配失败,它也不会再匹配第二条的规则。