# NATS 协议网关

EMQX Cloud 支持基于 [NATS Protocol](https://docs.nats.io/reference/reference-protocols/nats-protocol) 的 NATS 协议网关，用于接入 NATS 客户端并实现与 MQTT 的消息互通。

本页面介绍如何在 EMQX Cloud 中配置和使用 NATS 网关。

## 功能特性概览

NATS 协议网关当前支持以下主要功能：

### 协议支持

- **完整的 NATS 协议支持**：兼容以下报文类型：
  - 连接与会话管理：`INFO`、`CONNECT`
  - 消息发布与订阅：`PUB`、`HPUB`、`SUB`、`UNSUB`
  - 消息传递与响应：`MSG`、`HMSG`
  - 心跳与状态响应：`PING`、`PONG`、`+OK`、`-ERR`
- **Verbose 模式支持**：支持客户端通过 `CONNECT verbose=true` 开启消息确认响应。

### 协议互通能力（与 MQTT）

- **与 MQTT 的双向消息互通**：
  - NATS 客户端发布的消息可映射为 MQTT 消息发布。
  - MQTT 消息可转发给订阅了相应主题的 NATS 客户端。
- **支持 NATS 通配符订阅**，并自动转换为对应的 MQTT 主题格式。
- **支持 Queue Group（队列组）共享订阅**：NATS 客户端使用 Queue Group 订阅时，将被转换为 MQTT 的共享订阅格式。
- **支持 Request/Reply 模式**，包括以下能力：
  - NATS 客户端发送的请求消息可转为 MQTT 请求消息。
  - 若目标主题无任何订阅者，EMQX 网关可快速返回失败响应。

### 网络与连接能力

- **多种传输协议监听器**：支持 TCP、TLS、WebSocket (WS)、WebSocket over TLS (WSS) 四种类型的连接方式。

## 协议互通与消息映射

NATS 协议完全兼容发布订阅的消息模式，并和 MQTT 的发布订阅进行消息互通。NATS 网关的转换规则：

- NATS 协议的 PUB 和 HPUB 报文作为消息发布。
  - 其主题为 PUB 报文中的 `subject` 字段。 例如 Subject 为 `t.a` 会被 NATS 网关转换成为 MQTT 主题 `t/a` 进行发布。
  - 消息内容为 PUB 报文的消息体内容。
  - 当客户端连接 CONNECT 报文中的 `verbose=1` 时，转换消息的 QoS 固定 1；否则为 0。
- NATS 协议的 SUB 报文作为订阅请求。
  - 其主题为 SUB 报文中的 `subject` 字段。例如 Subject 为 `t.a` 会被 NATS 网关转换为 MQTT 主题 `t/a` 进行订阅。
  - 当客户端连接 CONNECT 报文中的 `verbose=1` 时，转换订阅的 QoS 固定 1；否则为 0。
  - 支持通配符，例如 `*.b.>` 会转换为 `+/b/#`。
  - 支持共享订阅。SUB 报文的 Queue Group 会被转换为 MQTT 共享订阅的组名。
- NATS 协议的 UNSUB 报文作为取消订阅请求。其主题为 UNSUB 报文中对应的订阅 ID。

网关内无独立的发布订阅的权限控制，其对主题的权限控制需要统一在[授权](../deployments/authz_overview.md)中管理。

## 当前功能限制

当前存在以下实现限制：

- 由于当前网关监听器不支持从 TCP 协议升级为 TLS 协议连接，所以暂不支持客户端以 `tls_handshake_first=false` 进行连接。
- 在未配置认证器时，支持未发起 CONNECT 报文的 NATS 客户端进行发布订阅，但目前暂不支持管理匿名客户端。

## 基本设置

点击 NATS 网关**操作**列中的**设置**按钮即可对网关进行基本设置：

- **服务名称**：网关的唯一标识名称，用于后续引用。默认值：`emq_nats_gateway`。

- **挂载点**: 设置一个字符串，为所有通过网关传输的发布订阅主题添加统一前缀，提供在不同协议之间实现消息路由隔离的方法，例如设置为 `nats/`。此主题前缀由网关管理，客户端在发布和订阅时无需显式添加此前缀。

- **默认心跳间隔**：服务端主动发送 PING 的时间间隔，用于探测客户端是否仍在线。默认值：`60` 秒。

- **心跳超时阈值**：如果客户端在该时间内未回应心跳，将被视为断开连接。默认值：`5` 秒。

- **最大消息负载大小**：单条 PUB/HPUB 消息的 Payload 最大字节数。默认值：`1048576` 字节。

- **空闲超时时间**: 设置连接客户端在无活动状态下被视为断开连接的持续时间（以秒为单位）。默认值：`30` 秒。

- **启用统计**: 设置是否允许网关收集和报告统计信息。默认为开启。

- **客户端信息覆盖**：客户端连接信息的覆盖策略，支持从 CONNECT 报文中提取客户端认证信息：

  ::: tip

  在启用认证器的情况下，应明确设置 `username` 和 `password` 的映射字段，以确保认证信息准确传递。

  :::

  - **用户名**：映射 CONNECT 报文中的 `user` 字段。
  - **密码**：映射 CONNECT 报文中的 `pass` 字段。
  - **客户端 ID**：可设置为 `${generated}` 由服务自动生成，或指定逻辑规则。

完成设置后，点击**更新**保存设置。

## 客户端

在 NATS 页面的**客户端**标签页中可以查看连接到部署的客户端的基本信息。在**操作**列中，可以选择将某一客户端踢除。

![nats_client](./_assets/nats_client.png)

## 认证管理

NATS 协议支持多种认证方式，包括用户名/密码、Token 认证等。NATS 网关支持以下多种认证器类型，例如：

- [密码认证](../deployments/auth_overview.md#密码认证-默认)
- [HTTP 认证](../deployments/http_auth.md)
- [MySQL 认证](../deployments/mysql_auth.md)
- [PostgreSQL 认证](../deployments/pgsql_auth.md)
- [Redis 认证](../deployments/redis_auth.md)
- [JWT 认证](../deployments/jwt_auth.md)

与 MQTT 协议不同，网关仅支持创建一个认证器，而不是认证器列表（或认证链）。当不启用任何认证器时，表示允许所有的 NATS 客户端都具有接入的权限。

NATS 网关使用 NATS 协议的 CONNECT 报文中的信息来生成客户端的认证信息。默认情况下：

- Client ID：为随机生成的字符串。
- Username：为 CONNECT 报文中的 `user` 字段的值。
- Password：为 CONNECT 报文中的 `pass` 字段的值。

您可以在网关页面，点击 NATS 网关**操作**列中的**接入认证**按钮进入到 NATS 认证管理页面，在该页面中添加、编辑或删除认证信息。

![nats_authn](./_assets/nats_authn.png)
