# @crvouga/mockingbird-service-emqx 中文文档

规范地址：https://npmcn.com/package/%40crvouga/mockingbird-service-emqx/

版本：0\.10\.0
npm 元数据更新时间：2026-11-11T02:11:54.135Z
中文译文更新时间：2026-11-11T06:23:30.278Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40crvouga/mockingbird-service-emqx
原文对照：https://npmcn.com/package/%40crvouga/mockingbird-service-emqx/?lang=original
项目主页：https://github.com/crvouga/mockingbird/tree/main/packages/service/emqx#readme
源码仓库：https://github.com/crvouga/mockingbird

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：4.8 MB，18 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- 首次发布：2026-10-11T01:56:12.557Z
- 最新版本发布：2026-11-11T02:11:53.677Z
- 近 30 天下载量：2962（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：19（近 12 个月 19 个）

## 中文简介

状态模拟器 EMQQQT 5 MQTT 经纪人: MQTT 5 超越 TCP 和 WebSocket, 密码和 JWT 认证 JWT ACLs, 有离线QoS 1 队列的持续会话, REST v5 发布和客户端 Kick 端点.

## 安装

```sh
npm install @crvouga/mockingbird-service-emqx
```

也可以使用：`pnpm add @crvouga/mockingbird-service-emqx`、`yarn add @crvouga/mockingbird-service-emqx`、`bun add @crvouga/mockingbird-service-emqx`

## README

# @crvouga/mockingbird-service-emqx (英语)

> 本地模拟器。 真正的API合同. 部分 [嘲笑鸟](https://github.com/crvouga/mockingbird)。 。 。 .

国家模拟器 **EMQX. 5** 测试套房和本地开发的MQTT经纪人:一个MQTT 5 tCP和WebSocket的经纪人(`/mqtt`),EMQX的密码和JWT认证与JWT ACLs, 持续会话带有离线的 QoS 1 队列, 而两个 REST v5 端点只发布 客户需求(`POST /api/v5/publish`, (中文(简体) ), `DELETE /api/v5/clients/{clientid}`) (中文(简体) ). 它在测试中运行 在 OS 指定端口上的进程,没有安装经纪人、 Docker 或本地二进制和会话 到期时间跟随一个时钟 套房移动而不是等待.

-   行动覆盖( HTTP): [支助](https://github.com/crvouga/mockingbird/blob/main/packages/service/emqx/SUPPORT.md)
-   没有EM Q经纪人作为甲骨文,所以行为跟随 [MQTT 5.0 规格](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html),则 [EMQX文档](https://docs.emqx.com/en/emqx/latest/) 和EMQX 5.8.6 来源。 什麽 未结算者列于下 [未核实](https://npmcn.com/package/%40crvouga/mockingbird-service-emqx/#readme-unverified)。 。 。 .

## 安装

```bash
npm install -D @crvouga/mockingbird-service-emqx
```

仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务 `npx mockingbird-emqx serve` 或者说 `createServer` 从 `./server` (节点和邦). `createRuntime` (默认条目)是可移植的: 它服务于 REST API over `fetch` 和 MQTT 通过 `runtime.attach`没有听者.

## 使用量

将应用程序的 MQTT URL 指向 `mqttUrl` (或 `wsUrl`),其EMQX API来源于 `url`,并给它 您在此配置的 API 密钥、 MQTT 用户和 JWT 密钥 .

```ts
import { createServer } from "@crvouga/mockingbird-service-emqx/server"
import mqtt from "mqtt"

const emqx = await createServer({
  settings: {
    apiKeys: [{ key: "test-key", secret: "test-secret" }],
    users: [{ username: "service", password: "service-password", superuser: true }],
    jwt: { secret: "test-jwt-secret" }, // HS256 token in the CONNECT password
    authorization: { noMatch: "deny" },
  },
})
// emqx.url      http://127.0.0.1:<port>       REST API and /__admin
// emqx.mqttUrl  mqtt://127.0.0.1:<port>       MQTT 5 over TCP
// emqx.wsUrl    ws://127.0.0.1:<port>/mqtt    MQTT 5 over WebSocket

const client = await mqtt.connectAsync(emqx.mqttUrl, {
  protocolVersion: 5,
  clientId: "device-1",
  clean: false,
  properties: { sessionExpiryInterval: 600 },
  username: "service",
  password: "service-password",
})
await client.subscribeAsync("space:example", { qos: 1 })

// EMQX publishes no JavaScript SDK for its REST API, so the publisher calls it over HTTP.
await fetch(`${emqx.url}/api/v5/publish`, {
  method: "POST",
  headers: {
    authorization: `Basic ${btoa("test-key:test-secret")}`,
    "content-type": "application/json",
  },
  body: JSON.stringify({ topic: "space:example", payload: "hello", qos: 1, retain: false }),
})

// Test control: move time instead of waiting for a session to expire.
await fetch(`${emqx.url}/__admin/clock`, { method: "POST", body: '{"advance": "600s"}' })

await client.endAsync()
await emqx.close() // closes every listener and drops every client
```

```bash
npx mockingbird-emqx serve --port 8850 --mqtt-port 1883 \
  --api-key test-key:test-secret --mqtt-user service:service-password \
  --jwt-secret test-jwt-secret --no-match deny
```

每个 `createServer()` 是它自己拥有自己的港口的经纪人,其中两个没有分享任何东西。 下 邦顿, `mqtt`节点 WebSocket 传输没有启动( Bun) `ws` 没有 `createWebSocketStream`,所以连接到 `wsUrl` 与库的浏览器传输 (单位:千美元)`new MqttClient((c) => browserStreamBuilder(c, options), options)` 从 `mqtt/lib/connect/ws`, (中文(简体) ), 或用途 `connectStream(runtime)` 从 `./server` 用于无套接字连接。 在平原的节点上 `mqtt.connect("ws://…/mqtt")` 工作时.

### MQTT 数据

MQTT 5.0 在TCP和WebSocket上运行 `/mqtt` (副议定书) `mqtt`,还有 `mqtt-v3`, (中文(简体) ), `mqtt-v3.1.1`, (中文(简体) ), `mqtt-v5`; 没有更新的升级被解答 `400`,正如 EM 所做的那样 `fail_if_no_subprotocol`) (中文(简体) ). 两种运输方式都达到相同的会话.

| 包装 | 行为 |
| --- | --- |
| 连接/连接 | 规格中的 Clean Start 和会话过期间隔 : `clean: false` 恢复存储会话( c)`sessionPresent: true`),一个干净的开始丢弃它. EMQ按发送的客户端间隔. CONNACK载有最大包尺寸1048576,Topic Alias 最大65535,接受最大订阅32,Wildcard 订阅可用 1,订阅识别符可用 1,以及此仿真器无法做到的: 最大QoS 1,保留可用 0,共享订阅可用 0. 空客户端 ID 被指定 16 个字符 . |
| 认证 | EM-Q的链:内置数据库`users`),然后是JWT认证器(英语:`jwt`) (中文(简体) ). 没有配置任何连接, 如在新鲜的EMQX上。 错误的密码是 CONNACK `0x86`; 用来验证但已过期的标志( 或 已过期) `exp`),目前无效(`nbf`),失败 `verify_claims` 或有缺陷 `acl` 实值 `0x86`;不验证或认证人不承认的证书是 `0x87`。 。 。 . |
| 第二 CONNECT 有连接客户端 ID | 旧的连接得到DICONNECT `0x8E` 会议结束;新的会议恢复会议,除非它要求有一个干净的开始. |
| 子公司/分公司 | 精确过滤器和 `+` 编号 : `#` 通配符,无本地,订阅标识符. 授予的QoS最多1分. 拒绝的过滤器是 SUBACK `0x87`· ; `$share/…` 实值 `0x9E`。 。 。 . |
| PUBLISH / PUBACK 软件 | Qos 0和1. PUBACK为 `0x00`, (中文(简体) ), `0x10` 或 `0x87` 被拒绝时( 信件被丢弃; 被拒绝的QoS 0 发布被悄悄地丢弃) 。 属性(内容类型,响应话题,关联数据,用户属性,有效载荷格式指标,消息过期间隔)被转发. 入门专题别名能用. |
| 离线 | 连接已去掉的会话会保留订阅并排队列信件(Qos 0 too, as `mqtt.mqueue_store_qos0`; 最多1 000起,最老的下降,因为 `mqtt.max_mqueue_len`) (中文(简体) ). 发送和未确认的信息在复刊时会遭到DUP的不满。 最多32个QoS 1信息正在飞行中(`mqtt.max_inflight`),如果客户端的"接收最大"更低. |
| 会话到期 | `Session Expiry Interval` 连接结束后秒,在模拟时钟上. `0` (或缺席)以连接结束会话. |
| JWT 过期 | 与 `disconnectAfterExpire` (EMQ) 连接的客户端被发送到 DICONNECT `0x87` 当它的标志 `exp` 过关了 连接中断了 ACL否认一切. |

**JWT ACL. (英语).** 标志 `acl` 索赔(可配置名称)先问:

-   对象形式, `{"pub": [...], "sub": [...], "all": [...]}`: 允许列出的主题 其它的都被否认了.
-   名单表, `[{"permission": "allow" | "deny", "action": "pub" | "sub" | "all", "topic": "…", "qos"?: [0, 1], "retain"?: false}]`: 第一个匹配规则决定;一个没有匹配规则的主题 归为 `authorization.noMatch` (单位:千美元)`allow` 默认, 如 EMQX 5; EMQX 6 更改了默认 改为 `deny`) (中文(简体) ).

ACL 主题为 MQTT 过滤器 `${clientid}` 财务报告和审定财务报表 `${username}` 扩大; `eq <topic>` 比较 从字面上说 请求的过滤器按文字匹配, 所以规则 `a/+` 涵盖a 订阅 `a/#` (EMQX `emqx_topic:match/2`) (中文(简体) ). 一个超级用户来自 `users` 跳过 授权。 与 `authorization.denyAction: "disconnect"` 拒绝操作结束 连接到 DISCONNECT `0x87` 换句话说.

模拟器的模型 经纪人做什么 一个话题,没有其他的: `space:example` 是一个 主题级别。 将应用程序的逻辑名称映射到主题上是客户端的工作.

### 路线

每条路线都需要 `Authorization: Basic <api key>:<secret>`与 `apiKeys` 清空任意一对 被接受; 丢失的页眉总是被拒绝.

| 路线 | 行为 |
| --- | --- |
| `POST /api/v5/publish` | 贾森 `{topic, payload, qos?: 0|1|2, retain?, payload_encoding?: "plain"|"base64", properties?}`。 。 。 . `200 {"id": "<32 hex>"}` 当至少匹配一个会话( 离线的会话计数: 消息已排队); `202 {"reason_code": 16, "message": "no_matching_subscribers"}` 那时没有人知道. `400 {"code": "BAD_REQUEST", "message"}` 对于一个失败的人体 `topic`,非字符串 `payload`, (中文(简体) ), `qos` 超出范围、未知字段、无效的JSON); `400 {"reason_code": 144, "message": "topic_name_invalid"}` 空题或带有通配符; `400 {"reason_code": 151, "message": "packet_too_large"}` 超过 1 MB ; `415` 当身体不是 `application/json`. QoS 2 接受并交付给 订阅的QoS. |
| `DELETE /api/v5/clients/{clientid}` | 踢出客户端: 一个连接的客户端获得 DICONNECT `0x98` 行政行动、届会、订阅和排行被丢弃(离线会话也是如此). `204`,或 `404 {"code": "CLIENTID_NOT_FOUND", "message": "Client ID not found"}`。 。 。 . |
| 任何,无全权证书 | `401 {"code": "AUTHORIZATION_HEADER_ERROR", "message": "Support authorization: basic/bearer "}`; 错误的密钥或密钥是 `401 {"code": "BAD_API_KEY_OR_SECRET", "message": "Check api_key/api_secret"}`; 无记名符号是 `401 BAD_TOKEN`全部携带 `WWW-Authenticate: Basic Realm="emqx-dashboard"`。 。 。 . |

### 管理员(超过标准合同)

| 路线 | 效果 |
| --- | --- |
| `GET /__admin/clients` | 每届会议: `clientId`, (中文(简体) ), `username`, (中文(简体) ), `connected`, (中文(简体) ), `transport`, (中文(简体) ), `sessionExpiryInterval`, (中文(简体) ), `connectedAt`, (中文(简体) ), `disconnectedAt`, (中文(简体) ), `expiresAt`和计数 `subscriptions`, (中文(简体) ), `queued` 财务报告和审定财务报表 `inflight` 留言. |
| `GET /__admin/clients/:clientId` | 一届会议,订阅日期 `topics`。 。 。 . |
| `GET /__admin/subscriptions?clientId=` | 订阅: `topicFilter`,准予 `qos`,选项. |
| `GET /__admin/publishes` | `{total, publishes}`: 以元数据形式出版的上千种`topic`, (中文(简体) ), `qos`, (中文(简体) ), `bytes`, (中文(简体) ), `source: "mqtt" | "http" | "admin"`, (中文(简体) ), `clientId`, (中文(简体) ), `matched`, (中文(简体) ), `at`) (中文(简体) ). 有效载荷从不保存. |
| `POST /__admin/inject` | `{topic, payload | payloadBase64, qos?: 0 | 1}`: 向主题的订阅者发送生字节,绕过REST schema和每个ACL. 用它来给消费者一个有效载荷 它必须拒绝。 答复 `{matched}`。 。 。 . |
| `POST /__admin/transport/cut` | `{clientId?}`:一个客户端或所有客户端的网络断电. 现场连接因没有DICONNECT而死亡,新的CONNECT被放弃,没有得到答复. 会话未受影响,按自己的时间安排过期. |
| `POST /__admin/transport/restore` | `{clientId?}`:结束停产. `GET /__admin/transport` 列出切出的内容. |
| `POST /__admin/clients/:clientId/disconnect` | `{reasonCode?}`: 发送 DICONNECT( 默认) `0x98`)并收紧. 和卖家的踢球不同,会话会留下来. |
| `GET` 编号 : `PUT /__admin/settings` | `{apiKeys?, users?, jwt?: {secret, from?, aclClaimName?, verifyClaims?, secretBase64Encoded?, disconnectAfterExpire?} | null, authorization?: {noMatch?, denyAction?}}` 呼叫的命名空间。 重置运行时间创建的值的返回 . |
| `POST /__admin/clock` | 标准 将时钟一并移走 : 会话经过间隔会被丢弃, 带有过期符的客户端被断开 . |
| `POST /__admin/reset`检查站 | 标准 重置会降低每个连接和会话 。 恢复检查点会恢复会话、订阅和排队,并减少直播连接(检查点不能持有套接字). |

错误预设( E)`POST /__admin/faults {"preset": "<name>", "count"?: n}`· ; `GET /__admin/faults/presets`: `connect_bad_credentials` (结束) `0x86`, (中文(简体) ), `connect_not_authorized` (单位:千美元)`0x87`, (中文(简体) ), `connect_server_unavailable` (单位:千美元)`0x88`, (中文(简体) ), `publish_unavailable` (REST发布答案) `503 {"reason_code": 131, "message": "failed_to_dispatch"}`, (中文(简体) ), `api_unauthorized` (每一次紧急呼叫) 答题 `401`) (中文(简体) ). CONNECT是故障操作 `MqttConnect`,所以任何原因代码都可以是 强制 : `{"operationId": "MqttConnect", "effect": "connack", "params": {"reasonCode": 151}}`。 。 。 .

### 命名空间

平行工人通过命名空间孤立自己. HTTP : (韩语) `x-mockingbird-namespace`页:1 `/__admin/ns/<name>` aPI 来源或 API 密钥上的前缀 (单位:千美元)`PUT /__admin/credentials {"credentials": {"<api key>": "<namespace>"}}`. MQTT: WebSocket (英语) 網址 `ws://…/__admin/ns/<name>/mqtt`,或CONNECT用户名所按的同一证书地图, 然后,它的客户身份。 未映射的客户端使用默认的名称空间 .

### 未核实

取自EMQX 5.8.6 来源或未打开,未观察到在经纪人身上:

-   这个 `message` 计划文本 `400` (EMQ) 打印其配置库的错误; 模拟器 指纹 `{"kind": "validation_error", "path": "root.<field>", "reason": …}`),基础差64 载荷和未知路径 `404`。 。 。 .
-   EM 强制整数 `payload` 以至其小数字符串;模拟者拒绝.
-   CONNACK接收最大值是EMQQ `min(client's, 32)`;模拟器总是发出32.
-   这个 `is_superuser` 符号索赔不读取.

### 故意不模拟

-   MQTT 3.1和3.1.1:这种CONNECT以协议的回码被拒绝.
-   QoS 2: CONNACK表示最大QoS 1,一个QoS 2的订阅获得QoS 1,一个QoS 2 发布是回答 DISCONNECT `0x9B`.EMQX本身支持QoS 2.
-   保留信件: CONNACK 表示保留可用 0, 保留的出版物被回答 分解系统 `0x9A`,以及 `retain: true` 记录显示 `400`。 。 。 .
-   将信件(收录于CONNECT,从未出版),共享订阅,增强 认证( AUTH ), 留守超时( PINGREQ 已回答; 使用已死亡的运算切换) 连接、 消息过期、 和外出主题别名 .
-   公用钥匙和JWKS代号、密码散列、以及核证人或授权人以外的 内置数据库和JWT.
-   集群、仪表板及其登录标志、规则引擎、桥梁、计费、TLS和 听众配置 .

## API 密码

| 导出 | 仁爱 | 说明 |
| --- | --- | --- |
| `createRuntime` | 函数 | 服务合同的模拟者。 选项 : `settings`, (中文(简体) ), `clock`, (中文(简体) ), `seed`, (中文(简体) ), `adminPrefix`, (中文(简体) ), `adminKey`, (中文(简体) ), `onLog`, (中文(简体) ), `sqlite`添加 `attach(transport, info?, namespace?)` 为 MQTT 连接, `webSocketPath(pathname)`, (中文(简体) ), `endpoints`,以及 `stop()`。 。 。 . |
| `EmqxAPI` | 类 | 一个名字空间的经纪人: `fetch(request)` 用于rest API, `broker` 为MQTT, `state`, (中文(简体) ), `reset()`选项: `sqlite`, (中文(简体) ), `now`, (中文(简体) ), `namespace`, (中文(简体) ), `settings`, (中文(简体) ), `connectFault`。 。 。 . |
| `EMQX_PRESETS` | 对象 | 每个命名的断层预设. |
| `EMQX_NAMESPACE` | 字符串 | 服务名称, `"emqx"`。 。 。 . |
| `MQTT_CONNECT_OPERATION` | 字符串 | `"MqttConnect"`,操作id一个错误规则用于CONNECT. |
| `MQTT_WEBSOCKET_PATH` | 字符串 | `"/mqtt"`。 。 。 . |
| `MAX_PACKET_SIZE` | 编号 | `1048576`,EMQX's `mqtt.max_packet_size`。 。 。 . |
| `DEFAULT_SETTINGS`, (中文(简体) ), `DEFAULT_JWT_AUTHENTICATOR` | 对象 | 新鲜的EMQ:没有认证器, `no_match = allow`;和JWT验证器的默认值. |
| `apiKeyCredential` | 函数 | 请求的 API 密钥( 如何将证书映射到命名空间 ) . |
| `parseAcl`, (中文(简体) ), `checkAcl` | 函数 | 分析一个 `acl` 权利要求,并询问有关一个出版物或订阅者的情况(`allow`, (中文(简体) ), `deny` 或者说 `nomatch`) (中文(简体) ). |
| `ReasonCode` | 对象 | MQTT 5 名下理性码. |
| `document`, (中文(简体) ), `operationIds`, (中文(简体) ), `supportedOperationIds` | 数值 | REST合同及其操作代号. |
| `createServer`, (中文(简体) ), `connectStream`, (中文(简体) ), `serveTarget`, (中文(简体) ), `DEFAULT_PORT`, (中文(简体) ), `DEFAULT_MQTT_PORT` (单位:千美元)`./server`(中文(简体) ) | 节点 | 服务HTTP、WebSocket和TCP`{url, mqttUrl, mqttPort, wsUrl, runtime, close()}`; 选项添加 `port`, (中文(简体) ), `mqttPort`, (中文(简体) ), `host`, (中文(简体) ), `sweepMs`; 正在处理的 MQTT 流 `serve` CLI目标;港口8850和1883. |

部分 [嘲笑鸟](https://github.com/crvouga/mockingbird)。 。 。 .

## 常见问题

### @crvouga/mockingbird-service-emqx 是什么？

状态模拟器 EMQQQT 5 MQTT 经纪人: MQTT 5 超越 TCP 和 WebSocket, 密码和 JWT 认证 JWT ACLs, 有离线QoS 1 队列的持续会话, REST v5 发布和客户端 Kick 端点\.

### 如何安装 @crvouga/mockingbird-service-emqx？

在项目目录运行 npm install @crvouga/mockingbird-service-emqx，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 mockingbird-emqx，可以用 npx mockingbird-emqx 直接运行。

### @crvouga/mockingbird-service-emqx 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @crvouga/mockingbird-service-emqx 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @crvouga/mockingbird-service-emqx 可以商用吗？

@crvouga/mockingbird-service-emqx 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @crvouga/mockingbird-service-emqx 的下载量有多少？

根据 npm 官方下载统计，@crvouga/mockingbird-service-emqx 在 2026/10/11 – 2026/11/09 这 30 天内被下载 2,962 次，日均约 99 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @crvouga/mockingbird-service-emqx 还在维护吗？

最新版本 0\.10\.0 发布于 2026/11/11（今天）；至今共发布 19 个版本，其中过去 12 个月发布了 19 个；首次发布于 2026/10/11。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

