# 使用数据集成获取连接确认事件主题消息

**连接确认事件主题** `$events/client_connack` 会在服务端向客户端发送 CONNACK 报文时触发。`reason_code` 字段可用于判定连接是否成功，并指示失败的具体原因，为排查客户端连接失败问题提供了重要线索。虽然普通客户端无法直接订阅该主题，但可以通过规则引擎捕获事件消息，用于写入数据库、转发至其他主题或执行实时监控与分析等后续处理。

由于 EMQX Broker 作为 MQTT Broker 而非存储服务，并受安全隐私限制，默认不会保存客户端的历史状态记录或调试级别事件日志信息。因此，建议在部署中使用连接确认事件主题配置**数据集成规则**，以实时掌握设备连接情况并保留必要的行为记录，这对于后续的问题排查和审计分析都具有重要意义。

本页将介绍连接确认事件主题的使用场景，演示如何通过规则引擎捕获事件主题消息并进行处理，并使用 [MQTTX Desktop](https://mqttx.app/zh) 模拟客户端接收事件主题消息。

## 应用场景

连接确认事件主题可用于多种场景，包括：

- **排查连接失败原因**：捕获并记录客户端连接失败的 `reason_code` 和相关信息，帮助快速定位问题来源。   
- **监控设备接入质量**：实时掌握客户端的连接尝试情况，识别频繁连接失败的设备或区域，从而优化接入配置、网络条件或鉴权策略。
- **安全审计与访问追踪**：记录连接确认事件中的客户端信息至外部平台，为安全审计与合规分析提供数据支撑。

## 触发条件与关键字段

### 连接确认事件 ("$events/client\_connack")

- **触发条件**：服务端向客户端发送 CONNACK 报文时触发。
- **关键字段**：

| 字段            | 解释                                                           |
|-----------------|----------------------------------------------------------------|
| reason_code     | 各种原因代码                                           |
| clientid        | 成功连接的 Client ID                                           |
| username        | 成功连接的用户名                                               |
| peername        | 客户端连接的 IP 地址和端口                                     |
| keepalive       | MQTT 保活间隔 (客户端向 Broker 定期发送心跳消息的时间间隔)     |
| clean_start     | MQTT clean_start (客户端是否复用已存在的会话)                  |
| expiry_interval | MQTT Session 过期时间 (客户端会话在断开连接后应保留的最长时间) |
| timestamp       | timestamp - 事件触发的时间戳 (单位：毫秒)                          |

::: tip

连接确认事件主题的完整字段信息，请参阅官方文档：[客户端事件](../rule_engine/rule_engine_events.md#连接确认事件-events-client_connack)。

:::

## 连接失败场景分析

连接确认事件主题中的 `reason_code` 字段提供了连接错误的具体原因，有助于深入理解连接问题并优化客户端连接逻辑。`reason_code` 字段在 MQTT v3.1.1 中定义了以下原因码：

| 原因码           | 解释                                                           |
|-----------------|----------------------------------------------------------------|
| connection_accepted        | 客户端已成功连接到服务端。                                   |
| unacceptable_protocol_version        | 服务端不支持客户端请求的 MQTT 协议。通常发生在客户端使用了与服务端不支持的协议版本，或者客户端指定了一个错误的协议版本或协议名。             |
| client_identifier_not_valid        | 客户端提供的 ID 虽然符合 UTF-8 编码规范，但服务端不允许。例如设置 Clean Start 为 0 但 Client ID 为空，或 Client ID 超出服务端允许的长度限制。                      |
| server_unavailable       | 网络连接已建立，但服务端暂时不可用。这可能是由于系统负载过高，或当前服务端认证服务异常等等。    |
| malformed_username_or_password     | 客户端提供的用户名或密码格式不正确，导致认证失败。常见问题包括非法字符、编码错误或字段缺失。            |
| unauthorized_client | 客户端未获得连接权限。可能是认证信息无效，或客户端尝试进行未授权的操作，被服务端拒绝。 |

在 MQTT 5.0 中， `reason_code` 的种类大幅增加，使客户端能够更精确地识别和定位连接失败的具体原因。常见原因码包括：

| 原因码           | 解释                                                            |
|-----------------|----------------------------------------------------------------|
| success | 连接成功，客户端已被服务端接受。 |
| unspecified_error | 未指定的错误，表示某一方不希望向另一方透露错误的具体原因，或者协议规范中没有能够匹配当前情况的原因码。 |
| malformed_packet | 客户端发送的连接报文格式错误，例如字段缺失或编码不符合协议规范。 |
| protocol_error | 协议使用不当，客户端发送了违反 MQTT 协议规范的请求。常见情况包括在同一连接内发送多个 CONNECT 报文、报文中重复属性，或属性值不合法。 |
| implementation_specific_error | 报文有效，但当前服务端的实现不接受该报文，导致连接被拒绝。 |
| unacceptable_protocol_version | 服务端不支持客户端请求的 MQTT 协议。通常发生在客户端使用了与服务端不支持的协议版本，或者客户端指定了一个错误的协议版本或协议名。 |
| client_identifier_not_valid | 客户端提供的 ID 虽然符合 UTF-8 编码规范，但服务端不允许。设置 Clean Start 为 0 但 Client ID 为空，或 Client ID 超出服务端允许的长度限制。 |
| bad_username_or_password | 客户端使用了错误的用户名或密码，将被拒绝连接。 |
| not_authorized | 客户端未获得授权，通常是因为没有匹配到对应的用户名。 |
| server_unavailable | 网络连接已建立，但服务端暂时不可用。这可能是由于系统负载过高，或当前服务端认证服务异常等等。 |
| server_busy | 服务端繁忙，无法处理新的连接请求，请稍后再试。 |
| banned | 客户端被禁止连接，可能由于异常连接行为被列入黑名单，或被管理员手动封禁。 |
| bad_authentication_method | 客户端使用了服务端不支持的认证方法，或在重新认证时更改了认证方式。 |
| topic_name_invalid | 主题名的格式正确，但是不被客户端或服务端接受。 |
| packet_too_large | 报文超过客户端或服务端允许的最大长度。例如在 CONNECT 报文中设置了过大的遗嘱消息。 |
| quota_exceeded | 客户端的连接数量超出服务端的限额。 |
| retain_not_supported | 服务端不支持保留消息，但客户端在连接时将遗嘱消息设置为保留消息。 |
| qos_not_supported | 服务端不支持客户端请求的 QoS 等级。例如 CONNECT 报文中的遗嘱消息设置了超出服务器允许的 QoS 等级。 |
| use_another_server | 服务端告知客户端应该临时切换到另一个服务端。 |
| server_moved | 服务器迁移，服务端告知客户端应该永久切换到另一个服务端。 |
| connection_rate_exceeded | 客户端连接速率超出服务端限制，通常由于频繁重连或异常连接行为导致。 |

## 配置数据集成获取事件主题消息

在实际使用中，事件主题通常有以下两种处理方式：

1. **消息重发布**：将事件主题消息重新发布到其他 MQTT 主题。这种方式轻量、实时性强，并且与 MQTT 原生生态兼容，适合在系统内部快速消费和处理事件。
2. **转发至外部服务**：将事件主题消息发送至外部系统，如数据库、消息队列或 HTTP 服务。该方式支持与各种外部系统集成，便于实现实时响应和持久化处理。

本页仅演示消息重发布和转发至 HTTP 服务的方法，其他转发至不同数据库或外部服务的方式可参考官方文档：[EMQX Cloud 数据集成](../data_integration/introduction.md)。

### 消息重发布

本节将演示如何将连接确认事件主题消息重新发布至其他主题。

#### 创建规则和动作

1. 在**数据集成**页面中的**数据转发**服务分类下点击**消息重新发布**。如果已经创建过其他的连接器，则点击**新建连接器**，然后在**数据转发** 服务分类下选择**消息重新发布**。
2. 在 **SQL 编辑器** 中定义规则 SQL。如需排查客户端连接失败事件，可参考以下 SQL 示例：
``` SQL
SELECT
    clientid,
    username,
    reason_code,
    timestamp
FROM
    "$events/client_connack"
```
3. 点击**下一步**，添加动作。 
4. 在**创建动作**步骤页中，配置以下信息：
    - **使用连接器**：使用默认选项`消息重新发布`。
    - **主题**：设置目标主题为 `client_connack`。
    - **Payload**、**QoS** 和 **Retain**： 使用默认值。
5. 点击**确定**完成配置。
   
#### 测试规则和动作

推荐使用 [MQTTX](https://mqttx.app/) 模拟客户端连接与消息上报，同时您也可以使用其他任意客户端完成。

1. 使用 MQTTX 创建一个连接到部署，将 ClientID 设置为 `sub`。
2. 使用客户端 `sub` 订阅接收重发布消息的主题 `client_connack`。
3. 再创建一个连接 `conn` 到部署，此时客户端 `sub` 应该能收到以下格式的事件主题消息：
```json
{
    "clientid": "conn",
    "username": "u_emqx",
    "reason_code": "success",
    "timestamp": 1645003578856
}
```

### 转发事件主题消息至 HTTP 服务

本节将演示如何将连接确认事件主题消息转发至 HTTP 服务。开始之前，您需要创建 [VPC 对等连接](../deployments/vpc_peering.md)以通过内部网络 IP 访问目标连接器。或者开通 [NAT 网关](../vas/nat-gateway.md)，通过公网 IP 访问目标连接器。

#### 创建 HTTP Server 连接器

1. 在部署菜单中选择**数据集成**，在 **Web 服务**分类下选择 **HTTP 服务**。如果已经创建过其他连接器，选择**新建连接器**，然后在 **Web 服务**分类下选择 **HTTP 服务**。
2. 在**创建连接器**页面中填写 URL，其他配置项可按需调整。URL 应指向将接收事件消息的目标 HTTP 服务。连接器会按照规则中定义的 payload 向该 URL 发送 POST 请求。
3. 点击**测试**按钮测试连接，如果 HTTP 服务能够正常访问，则会返回成功提示。
4. 点击**新建**按钮完成配置。
   
#### 创建规则和动作

1. 点击**新建规则**进入新建规则步骤页。
2. 在 **SQL 编辑器**中定义规则 SQL。如需排查客户端断连事件，可参考以下 SQL 示例：
   
```sql
SELECT
    clientid,
    username,
    reason_code,
    timestamp
FROM
    "$events/client_connack"
```
3. 点击**下一步**开始创建动作。 

4. 从**使用连接器**下拉框中选择之前创建的 HTTP Server 连接器。剩下的配置保持默认值。

5. 点击**确认**按钮完成规则创建。

::: tip

  关于将数据转发至 HTTP 服务的完整流程与配置，可参考官方文档：[将 MQTT 数据发送到 HTTP 服务](../data_integration/http_server.md)。

:::    

#### 测试规则和动作

推荐使用 [MQTTX](https://mqttx.app/) 模拟客户端连接与消息上报，同时您也可以使用其他任意客户端完成。

1. 使用 MQTTX 连接到部署，将 ClientID 设置为 `conn`。 
2. 此时 HTTP 服务应该能收到 POST 请求，请求体原始内容的格式为：
```json
{
    "clientid": "conn",
    "username": "u_emqx",
    "reason_code": "success",
    "timestamp": 1645003578856
}
```