@danqiusheng/nest-nacos 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -21
  3. package/README.en.md +197 -0
  4. package/README.md +353 -385
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/nacos-config.service.d.ts +25 -45
  10. package/dist/nacos-config.service.d.ts.map +1 -1
  11. package/dist/nacos-config.service.js +241 -102
  12. package/dist/nacos-config.service.js.map +1 -1
  13. package/dist/nacos-naming.service.d.ts +16 -46
  14. package/dist/nacos-naming.service.d.ts.map +1 -1
  15. package/dist/nacos-naming.service.js +119 -88
  16. package/dist/nacos-naming.service.js.map +1 -1
  17. package/dist/nacos.decorators.d.ts +0 -4
  18. package/dist/nacos.decorators.d.ts.map +1 -1
  19. package/dist/nacos.decorators.js +1 -12
  20. package/dist/nacos.decorators.js.map +1 -1
  21. package/dist/nacos.health.d.ts +2 -6
  22. package/dist/nacos.health.d.ts.map +1 -1
  23. package/dist/nacos.health.js +5 -25
  24. package/dist/nacos.health.js.map +1 -1
  25. package/dist/nacos.interfaces.d.ts +85 -57
  26. package/dist/nacos.interfaces.d.ts.map +1 -1
  27. package/dist/nacos.module.d.ts +2 -11
  28. package/dist/nacos.module.d.ts.map +1 -1
  29. package/dist/nacos.module.js +22 -19
  30. package/dist/nacos.module.js.map +1 -1
  31. package/dist/nacos.providers.d.ts +4 -11
  32. package/dist/nacos.providers.d.ts.map +1 -1
  33. package/dist/nacos.providers.js +37 -23
  34. package/dist/nacos.providers.js.map +1 -1
  35. package/dist/nacos.utils.d.ts +6 -0
  36. package/dist/nacos.utils.d.ts.map +1 -0
  37. package/dist/nacos.utils.js +79 -0
  38. package/dist/nacos.utils.js.map +1 -0
  39. package/package.json +19 -10
package/README.md CHANGED
@@ -1,194 +1,77 @@
1
- # nest-nacos 使用文档
1
+ # @danqiusheng/nest-nacos
2
2
 
3
- > NestJS Nacos 插件 —— 服务发现 + 配置中心,基于 [nacos-sdk-nodejs](https://github.com/nacos-group/nacos-sdk-nodejs),支持 gRPC 传输协议(Nacos 2.x / 3.x)。
3
+ 面向 NestJS 10/11 Nacos 2.x 配置中心与服务注册发现模块。
4
4
 
5
- **版本**:v1.0.0 | **License**:MIT
6
-
7
- ---
8
-
9
- ## 目录
10
-
11
- 1. [介绍](#1-介绍)
12
- 2. [安装](#2-安装)
13
- 3. [快速开始](#3-快速开始)
14
- 4. [同步配置 forRoot](#4-同步配置-forroot)
15
- 5. [异步配置 forRootAsync](#5-异步配置-forrootasync)
16
- 6. [服务发现](#6-服务发现)
17
- 7. [配置中心](#7-配置中心)
18
- 8. [装饰器](#8-装饰器)
19
- 9. [健康检查](#9-健康检查)
20
- 10. [API: NacosNamingService](#10-api-nacosnamingservice)
21
- 11. [API: NacosConfigService](#11-api-nacosconfigservice)
22
- 12. [配置项参考](#12-配置项参考)
23
- 13. [常见问题](#13-常见问题)
24
-
25
- ---
26
-
27
- ## 1. 介绍
28
-
29
- **nest-nacos** 是一个 NestJS 插件,封装了 `nacos-sdk-nodejs`,为 NestJS 应用提供 **服务发现** 和 **配置中心** 能力。基于 gRPC 传输协议,支持 Nacos 2.x / 3.x 服务端。
30
-
31
- ### 特性
32
-
33
- | 特性 | 说明 |
34
- |------|------|
35
- | 动态模块 | 支持 `forRoot` / `forRootAsync`,可配合 `@nestjs/config` 从环境变量读取配置 |
36
- | 自动注册 | 模块初始化时自动注册服务实例,销毁时自动注销,无需手动管理生命周期 |
37
- | 配置热更新 | 订阅配置变更,服务端实时推送,内置本地缓存与 JSON 解析 |
38
- | gRPC 传输 | 默认使用 gRPC,服务端实时推送,无需 UDP 端口,支持自动重连 |
39
- | 装饰器注入 | 提供 `@InjectNacosNaming` / `@InjectNacosConfig` 装饰器,简化依赖注入 |
40
- | 健康检查 | 内置 `NacosHealthIndicator`,可对接 `@nestjs/terminus` 暴露健康端点 |
41
-
42
- ### 兼容性
43
-
44
- | nest-nacos | nacos-sdk-nodejs | Nacos Server | 传输协议 |
45
- |---|---|---|---|
46
- | 1.x | 2.6.x | 3.x / 2.x | gRPC(默认)/ HTTP(仅 2.x) |
47
-
48
- ---
49
-
50
- ## 2. 安装
51
-
52
- ### 步骤 1:安装 nest-nacos 和 nacos SDK
53
-
54
- ```bash
55
- # 使用 npm
56
- npm install nest-nacos nacos
57
-
58
- # 使用 yarn
59
- yarn add nest-nacos nacos
60
-
61
- # 使用 pnpm
62
- pnpm add nest-nacos nacos
63
- ```
64
-
65
- ### 步骤 2:确保宿主依赖已安装
66
-
67
- 以下包是 peerDependencies,通常 NestJS 项目中已存在:
5
+ ## 1. 安装
68
6
 
69
7
  ```bash
70
- npm install @nestjs/common @nestjs/core reflect-metadata rxjs
8
+ npm install @danqiusheng/nest-nacos nacos
71
9
  ```
72
10
 
73
- ### 步骤 3:(可选)安装配置模块
11
+ ## 2. 最简接入
74
12
 
75
- 如果需要从 `.env` 文件读取 Nacos 配置,安装 `@nestjs/config`:
13
+ 未开启 Nacos 鉴权时,只需要一个地址:
76
14
 
77
- ```bash
78
- npm install @nestjs/config
79
- ```
80
-
81
- > **提示**:Nacos Server 版本选择:如果使用 Nacos 3.x,必须使用 gRPC 传输(默认)。HTTP 传输仅支持 Nacos 2.x。
82
-
83
- ---
84
-
85
- ## 3. 快速开始
86
-
87
- 以下是一个最小可用示例,展示如何在 `AppModule` 中同时启用服务发现和配置中心:
88
-
89
- ```typescript
15
+ ```ts
90
16
  import { Module } from '@nestjs/common';
91
- import { NacosModule } from 'nest-nacos';
17
+ import { NacosModule } from '@danqiusheng/nest-nacos';
92
18
 
93
19
  @Module({
94
- imports: [
95
- NacosModule.forRoot({
96
- naming: {
97
- serverList: '127.0.0.1:8848',
98
- username: 'nacos',
99
- password: 'nacos',
100
- },
101
- config: {
102
- serverAddr: '127.0.0.1:8848',
103
- },
104
- instances: [
105
- { serviceName: 'order-service', ip: '192.168.1.100', port: 3000 },
106
- ],
107
- }),
108
- ],
20
+ imports: [NacosModule.forRoot('127.0.0.1:8848')],
109
21
  })
110
22
  export class AppModule {}
111
23
  ```
112
24
 
113
- 应用启动后,nest-nacos 会自动:
25
+ 这会同时启用配置中心和服务注册发现,默认使用:
114
26
 
115
- - 连接 Nacos 服务端
116
- - 注册 `order-service` 实例(192.168.1.100:3000)
117
- - 应用关闭时自动注销该实例
27
+ | 配置 | 默认值 |
28
+ |---|---|
29
+ | namespace | `public` |
30
+ | group | `DEFAULT_GROUP` |
31
+ | transport | HTTP OpenAPI |
32
+ | 重试次数 | 3 次(包含第一次调用) |
118
33
 
119
- ---
34
+ 开启用户名密码鉴权时,也只需要配置一次连接信息:
120
35
 
121
- ## 4. 同步配置 forRoot
122
-
123
- 适用于配置固定的场景,直接在代码中写入连接参数:
36
+ ```ts
37
+ NacosModule.forRoot({
38
+ serverAddr: '127.0.0.1:8848',
39
+ username: 'nacos',
40
+ password: 'nacos',
41
+ });
42
+ ```
124
43
 
125
- ```typescript
126
- import { NacosModule } from 'nest-nacos';
44
+ `serverAddr` 支持集群地址数组:
127
45
 
46
+ ```ts
128
47
  NacosModule.forRoot({
129
- naming: {
130
- serverList: '127.0.0.1:8848',
131
- namespace: 'production',
132
- username: 'nacos',
133
- password: 'nacos',
134
- },
135
- config: {
136
- serverAddr: '127.0.0.1:8848',
137
- namespace: 'production',
138
- },
139
- // 启动时自动注册的实例
140
- instances: [
141
- {
142
- serviceName: 'order-service',
143
- ip: '192.168.1.100',
144
- port: 3000,
145
- weight: 1.0,
146
- metadata: { version: '1.0.0' },
147
- },
148
- ],
149
- // 启动时预订阅的配置项
150
- subscribeConfigs: [
151
- { dataId: 'database.yaml', group: 'DEFAULT_GROUP' },
152
- { dataId: 'redis.yaml', group: 'DEFAULT_GROUP' },
153
- ],
154
- })
48
+ serverAddr: ['10.0.0.11:8848', '10.0.0.12:8848'],
49
+ namespace: 'production',
50
+ username: process.env.NACOS_USERNAME,
51
+ password: process.env.NACOS_PASSWORD,
52
+ ssl: false,
53
+ });
155
54
  ```
156
55
 
157
- ---
158
-
159
- ## 5. 异步配置 forRootAsync
56
+ ## 3. 使用环境变量
160
57
 
161
- 适用于生产环境,配合 `@nestjs/config` 从环境变量或配置文件读取参数:
58
+ 插件不会隐式读取环境变量。推荐使用 Nest `ConfigModule` 明确传入配置:
162
59
 
163
- ```typescript
60
+ ```ts
164
61
  import { Module } from '@nestjs/common';
165
62
  import { ConfigModule, ConfigService } from '@nestjs/config';
166
- import { NacosModule } from 'nest-nacos';
63
+ import { NacosModule } from '@danqiusheng/nest-nacos';
167
64
 
168
65
  @Module({
169
66
  imports: [
170
67
  ConfigModule.forRoot({ isGlobal: true }),
171
68
  NacosModule.forRootAsync({
172
- imports: [ConfigModule],
173
69
  inject: [ConfigService],
174
70
  useFactory: (config: ConfigService) => ({
175
- naming: {
176
- serverList: config.get('NACOS_SERVER_ADDR'),
177
- namespace: config.get('NACOS_NAMESPACE'),
178
- username: config.get('NACOS_USERNAME'),
179
- password: config.get('NACOS_PASSWORD'),
180
- },
181
- config: {
182
- serverAddr: config.get('NACOS_SERVER_ADDR'),
183
- namespace: config.get('NACOS_NAMESPACE'),
184
- },
185
- instances: [
186
- {
187
- serviceName: config.get('SERVICE_NAME'),
188
- ip: config.get('SERVICE_IP'),
189
- port: config.get<number>('SERVICE_PORT'),
190
- },
191
- ],
71
+ serverAddr: config.getOrThrow<string>('NACOS_SERVER_ADDR'),
72
+ namespace: config.get<string>('NACOS_NAMESPACE') ?? 'public',
73
+ username: config.get<string>('NACOS_USERNAME'),
74
+ password: config.get<string>('NACOS_PASSWORD'),
192
75
  }),
193
76
  }),
194
77
  ],
@@ -196,314 +79,399 @@ import { NacosModule } from 'nest-nacos';
196
79
  export class AppModule {}
197
80
  ```
198
81
 
199
- 对应的 `.env` 文件:
82
+ `.env` 示例:
200
83
 
201
- ```env
84
+ ```dotenv
202
85
  NACOS_SERVER_ADDR=127.0.0.1:8848
203
86
  NACOS_NAMESPACE=public
204
87
  NACOS_USERNAME=nacos
205
88
  NACOS_PASSWORD=nacos
206
- SERVICE_NAME=order-service
207
- SERVICE_IP=192.168.1.100
208
- SERVICE_PORT=3000
209
89
  ```
210
90
 
211
- > **说明**:`forRootAsync` 还支持 `useClass` 和 `useExisting` 两种方式,适合需要从远程配置中心或数据库读取 Nacos 连接参数的场景。
91
+ `forRootAsync` 同时支持 `useFactory`、`useClass` 和 `useExisting`。
212
92
 
213
- ---
93
+ ## 4. 自动注册当前服务
214
94
 
215
- ## 6. 服务发现
95
+ 在模块配置中加入 `instances`,应用启动时自动注册,关闭时自动注销:
216
96
 
217
- 注入 `NacosNamingService` 即可使用服务注册与发现功能:
97
+ ```ts
98
+ NacosModule.forRoot({
99
+ serverAddr: '127.0.0.1:8848',
100
+ instances: [
101
+ {
102
+ serviceName: 'order-service',
103
+ ip: '192.168.1.20',
104
+ port: 3000,
105
+ weight: 1,
106
+ ephemeral: true,
107
+ metadata: { env: 'prod', version: '1.2.0' },
108
+ },
109
+ ],
110
+ });
111
+ ```
218
112
 
219
- ```typescript
220
- import { Injectable, OnModuleInit } from '@nestjs/common';
221
- import { NacosNamingService, InjectNacosNaming } from 'nest-nacos';
113
+ 如果 IP 或端口来自环境变量,应使用 `forRootAsync` 构造 `instances`。
222
114
 
223
- @Injectable()
224
- export class RpcService implements OnModuleInit {
225
- @InjectNacosNaming()
226
- private readonly naming: NacosNamingService;
227
-
228
- async onModuleInit() {
229
- // 订阅 user-service 实例变更(服务端推送)
230
- this.naming.subscribe('user-service', (hosts) => {
231
- console.log(`user-service 实例数: ${hosts.length}`);
232
- });
233
- }
115
+ ## 5. 服务注册与发现
234
116
 
235
- // 查询健康实例并调用
236
- async callUserService() {
237
- const instances = await this.naming.selectInstances('user-service');
238
- if (instances.length === 0) {
239
- throw new Error('user-service 无可用实例');
240
- }
241
- const target = instances[0];
242
- return `http://${target.ip}:${target.port}`;
243
- }
117
+ ### 注入服务
244
118
 
245
- // 运行时动态注册新实例
246
- async registerTemp() {
247
- await this.naming.register({
248
- serviceName: 'temp-service',
249
- ip: '10.0.0.5',
250
- port: 8080,
251
- ephemeral: true,
252
- });
253
- }
119
+ ```ts
120
+ import { Injectable } from '@nestjs/common';
121
+ import {
122
+ InjectNacosNaming,
123
+ NacosNamingService,
124
+ } from '@danqiusheng/nest-nacos';
125
+
126
+ @Injectable()
127
+ export class ServiceDiscovery {
128
+ constructor(
129
+ @InjectNacosNaming()
130
+ private readonly naming: NacosNamingService,
131
+ ) {}
254
132
  }
255
133
  ```
256
134
 
257
- ---
135
+ 也可以直接使用构造器注入 `NacosNamingService`。
258
136
 
259
- ## 7. 配置中心
137
+ ### 手动注册和注销
260
138
 
261
- 注入 `NacosConfigService` 即可读取和订阅配置:
139
+ ```ts
140
+ const instance = {
141
+ serviceName: 'payment-service',
142
+ ip: '192.168.1.30',
143
+ port: 3000,
144
+ metadata: { env: 'prod' },
145
+ };
262
146
 
263
- ```typescript
264
- import { Injectable, OnModuleInit } from '@nestjs/common';
265
- import { NacosConfigService, InjectNacosConfig } from 'nest-nacos';
147
+ await this.naming.register(instance);
148
+ await this.naming.deregister(instance);
149
+ ```
266
150
 
267
- @Injectable()
268
- export class DbService implements OnModuleInit {
269
- @InjectNacosConfig()
270
- private readonly nacosConfig: NacosConfigService;
151
+ 通过插件注册的实例会被记录,Nest 模块销毁时会自动注销。
271
152
 
272
- private dbConfig: any;
153
+ ### 获取健康实例
273
154
 
274
- async onModuleInit() {
275
- // 1. 读取配置(自动解析 JSON)
276
- this.dbConfig = await this.nacosConfig.getConfigAsJson('database.yaml');
155
+ ```ts
156
+ const instances = await this.naming.selectInstances('payment-service');
157
+ ```
277
158
 
278
- // 2. 订阅配置热更新
279
- this.nacosConfig.subscribe('database.yaml', 'DEFAULT_GROUP', (content) => {
280
- this.dbConfig = JSON.parse(content);
281
- console.log('数据库配置已热更新');
282
- });
283
- }
159
+ 只选择一个实例:
284
160
 
285
- async updateConfig() {
286
- // 发布新配置
287
- await this.nacosConfig.publish(
288
- 'database.yaml',
289
- 'DEFAULT_GROUP',
290
- JSON.stringify({ host: '10.0.0.1', port: 3306 }),
291
- );
292
- }
293
- }
161
+ ```ts
162
+ const instance = await this.naming.selectInstance('payment-service', {
163
+ strategy: 'roundRobin',
164
+ metadata: { env: 'prod' },
165
+ });
294
166
  ```
295
167
 
296
- > **缓存机制**:`getConfig()` 首次从 Nacos 拉取后会缓存到内存,后续调用直接返回缓存值。订阅配置变更时会自动更新缓存,无需手动管理。
168
+ 支持三种策略:
297
169
 
298
- ---
170
+ | strategy | 行为 |
171
+ |---|---|
172
+ | `random` | 随机选择,默认值 |
173
+ | `roundRobin` | 按服务轮询 |
174
+ | `weighted` | 按 Nacos 实例权重随机选择 |
299
175
 
300
- ## 8. 装饰器
176
+ 找不到满足健康状态和 metadata 条件的实例时,`selectInstance()` 会抛出异常。
301
177
 
302
- nest-nacos 提供四个装饰器简化依赖注入:
178
+ ### 订阅服务变化
303
179
 
304
- | 装饰器 | 注入对象 | 说明 |
305
- |--------|----------|------|
306
- | `@InjectNacosNaming()` | `NacosNamingService` | 注入封装后的 Naming 服务 |
307
- | `@InjectNacosConfig()` | `NacosConfigService` | 注入封装后的 Config 服务 |
308
- | `@InjectNacosNamingClient()` | `NacosNamingClient` | 注入原始 SDK 客户端(高级用法) |
309
- | `@InjectNacosConfigClient()` | `NacosConfigClient` | 注入原始 SDK 客户端(高级用法) |
180
+ ```ts
181
+ const listener = (hosts: unknown[]) => {
182
+ console.log('payment-service 实例变化', hosts);
183
+ };
310
184
 
311
- 使用示例:
185
+ this.naming.subscribe('payment-service', listener);
186
+ this.naming.unSubscribe('payment-service', listener);
187
+
188
+ // 不传 listener:取消该服务的全部本地订阅
189
+ this.naming.unSubscribe('payment-service');
190
+ ```
191
+
192
+ ### 更新权重
193
+
194
+ ```ts
195
+ await this.naming.updateWeight(instance, 0.5);
196
+ ```
312
197
 
313
- ```typescript
198
+ ## 6. 配置中心
199
+
200
+ ### 注入服务
201
+
202
+ ```ts
314
203
  import { Injectable } from '@nestjs/common';
315
204
  import {
316
- NacosNamingService,
317
- NacosConfigService,
318
- InjectNacosNaming,
319
205
  InjectNacosConfig,
320
- } from 'nest-nacos';
206
+ NacosConfigService,
207
+ } from '@danqiusheng/nest-nacos';
321
208
 
322
209
  @Injectable()
323
- export class MyService {
324
- @InjectNacosNaming()
325
- private readonly naming: NacosNamingService;
326
-
327
- @InjectNacosConfig()
328
- private readonly config: NacosConfigService;
329
-
330
- // 也可以用构造函数注入
210
+ export class SettingsService {
331
211
  constructor(
332
- private readonly naming2: NacosNamingService,
333
- private readonly config2: NacosConfigService,
212
+ @InjectNacosConfig()
213
+ private readonly nacos: NacosConfigService,
334
214
  ) {}
335
215
  }
336
216
  ```
337
217
 
338
- ---
218
+ ### 读取配置
219
+
220
+ ```ts
221
+ const raw = await this.nacos.getConfig('application.yaml');
222
+
223
+ const config = await this.nacos.getParsedConfig<{
224
+ server: { port: number };
225
+ }>('application.yaml');
226
+ ```
227
+
228
+ 格式默认根据 `dataId` 后缀自动识别:
229
+
230
+ | 后缀/format | 返回值 |
231
+ |---|---|
232
+ | `.json` / `json` | JSON 对象或数组 |
233
+ | `.yaml`、`.yml` / `yaml` | YAML 解析结果 |
234
+ | `.properties` / `properties` | 键值对象 |
235
+ | 其他 / `txt` | 原始字符串 |
236
+
237
+ 强制按 JSON 解析:
238
+
239
+ ```ts
240
+ const config = await this.nacos.getConfigAsJson<AppConfig>(
241
+ 'application.json',
242
+ );
243
+ ```
244
+
245
+ ### 发布和删除配置
246
+
247
+ ```ts
248
+ const published = await this.nacos.publish(
249
+ 'application.json',
250
+ 'DEFAULT_GROUP',
251
+ JSON.stringify({ featureEnabled: true }),
252
+ );
253
+
254
+ const removed = await this.nacos.remove(
255
+ 'application.json',
256
+ 'DEFAULT_GROUP',
257
+ );
258
+ ```
259
+
260
+ 返回值为 Nacos SDK 的最终布尔结果。public namespace 删除已处理 `tenant=public` 导致的假成功问题。
261
+
262
+ ### 订阅热更新
263
+
264
+ ```ts
265
+ const listener = (raw: string, parsed?: unknown) => {
266
+ console.log('配置已更新', parsed);
267
+ };
268
+
269
+ this.nacos.subscribe(
270
+ 'application.yaml',
271
+ 'DEFAULT_GROUP',
272
+ listener,
273
+ );
274
+
275
+ this.nacos.unSubscribe(
276
+ 'application.yaml',
277
+ 'DEFAULT_GROUP',
278
+ listener,
279
+ );
280
+ ```
281
+
282
+ 同一个 `dataId + group` 只建立一个底层 SDK 订阅,多个业务 listener 不会导致重复回调。
283
+
284
+ ## 7. 启动时预加载配置
285
+
286
+ ```ts
287
+ NacosModule.forRoot({
288
+ serverAddr: '127.0.0.1:8848',
289
+ subscribeConfigs: [
290
+ { dataId: 'application.yaml', format: 'yaml' },
291
+ { dataId: 'database.properties', format: 'properties' },
292
+ {
293
+ dataId: 'optional.json',
294
+ required: false,
295
+ subscribe: false,
296
+ },
297
+ ],
298
+ });
299
+ ```
300
+
301
+ 默认行为:
302
+
303
+ - group 为 `DEFAULT_GROUP`。
304
+ - format 为 `auto`。
305
+ - `subscribe: true`,预加载后继续监听热更新。
306
+ - `required: true`,读取失败会按启动失败策略处理。
307
+
308
+ 合并所有已声明配置:
309
+
310
+ ```ts
311
+ const merged = await this.nacos.getMergedConfig<AppConfig>();
312
+ ```
313
+
314
+ 对象会按声明顺序深度合并,后面的配置覆盖前面的同名字段。
315
+
316
+ ## 8. 本地缓存和启动失败策略
317
+
318
+ ```ts
319
+ NacosModule.forRoot({
320
+ serverAddr: '127.0.0.1:8848',
321
+ subscribeConfigs: [{ dataId: 'application.yaml' }],
322
+ configLoading: {
323
+ failureMode: 'fallback',
324
+ cacheDir: '.nacos-cache',
325
+ retry: {
326
+ attempts: 3,
327
+ delayMs: 300,
328
+ backoffFactor: 2,
329
+ maxDelayMs: 3000,
330
+ },
331
+ },
332
+ });
333
+ ```
334
+
335
+ | failureMode | 行为 |
336
+ |---|---|
337
+ | `throw` | 读取必需配置失败时阻止应用启动,默认值 |
338
+ | `fallback` | 优先读取本地缓存;无缓存且配置必需时阻止启动 |
339
+ | `continue` | 记录警告并继续启动 |
340
+
341
+ 成功从 Nacos 读取配置后,插件会原子更新缓存文件。缓存目录应加入部署持久化目录,不建议提交到 Git。
339
342
 
340
343
  ## 9. 健康检查
341
344
 
342
- 内置 `NacosHealthIndicator` 可对接 `@nestjs/terminus`:
345
+ `getServerStatus()` `isHealthy()` 都是异步方法:
346
+
347
+ ```ts
348
+ const status = await this.naming.getServerStatus(); // UP | DOWN
349
+ ```
350
+
351
+ 可直接提供 Nest HTTP 健康接口:
343
352
 
344
- ```typescript
353
+ ```ts
345
354
  import { Controller, Get } from '@nestjs/common';
346
- import { HealthCheckService } from '@nestjs/terminus';
347
- import { NacosHealthIndicator } from 'nest-nacos';
355
+ import { NacosHealthIndicator } from '@danqiusheng/nest-nacos';
348
356
 
349
- @Controller('health')
350
- export class HealthController {
351
- constructor(
352
- private health: HealthCheckService,
353
- private nacos: NacosHealthIndicator,
354
- ) {}
357
+ @Controller('health/nacos')
358
+ export class NacosHealthController {
359
+ constructor(private readonly health: NacosHealthIndicator) {}
355
360
 
356
361
  @Get()
357
362
  check() {
358
- return this.health.check([
359
- () => this.nacos.isHealthy(),
360
- ]);
363
+ return this.health.isHealthy();
361
364
  }
362
365
  }
363
366
  ```
364
367
 
365
- 如果未安装 `@nestjs/terminus`,也可直接调用 `isHealthy()` 方法,返回 `{ status: 'up' | 'down' }`。
368
+ 返回:
366
369
 
367
- ---
370
+ ```json
371
+ { "status": "up" }
372
+ ```
368
373
 
369
- ## 10. API: NacosNamingService
374
+ ## 10. 高级连接配置
370
375
 
371
- | 方法 | 参数 | 返回值 | 说明 |
372
- |------|------|--------|------|
373
- | `register(inst)` | `NacosInstanceOptions` | `Promise<void>` | 注册服务实例 |
374
- | `deregister(inst)` | `NacosInstanceOptions` | `Promise<void>` | 注销服务实例 |
375
- | `getAllInstances(serviceName, groupName?, clusters?, subscribe?)` | `string, ...` | `Promise<Host[]>` | 查询所有实例 |
376
- | `selectInstances(serviceName, groupName?, clusters?, healthy?, subscribe?)` | `string, ...` | `Promise<Host[]>` | 查询健康实例 |
377
- | `subscribe(info, listener)` | `string \| SubscribeInfo, Function` | `void` | 订阅实例变更推送 |
378
- | `unSubscribe(info, listener?)` | `string \| SubscribeInfo, Function?` | `void` | 取消订阅 |
379
- | `getServerStatus()` | 无 | `'UP' \| 'DOWN'` | 获取服务端状态 |
380
- | `getRawClient()` | 无 | `NacosNamingClient \| null` | 获取原始 SDK 客户端 |
376
+ 绝大多数项目只需要顶层共享配置。只有 Naming Config 使用不同地址、命名空间或云鉴权参数时,才使用嵌套配置:
381
377
 
382
- ### subscribe 参数说明
378
+ ```ts
379
+ NacosModule.forRoot({
380
+ serverAddr: 'shared-nacos:8848',
381
+ username: 'shared-user',
382
+ password: 'shared-password',
383
+
384
+ naming: {
385
+ serverList: 'naming-nacos:8848',
386
+ namespace: 'service-space',
387
+ appName: 'order-service',
388
+ },
389
+ config: {
390
+ serverAddr: 'config-nacos:8848',
391
+ namespace: 'config-space',
392
+ accessKey: process.env.NACOS_ACCESS_KEY,
393
+ secretKey: process.env.NACOS_SECRET_KEY,
394
+ },
395
+ });
396
+ ```
383
397
 
384
- `info` 参数支持两种形式:
398
+ 嵌套配置优先于顶层共享配置。只配置 `naming` 或只配置 `config`,可以只启用对应能力。
385
399
 
386
- ```typescript
387
- // 形式一:字符串(serviceName)
388
- naming.subscribe('user-service', (hosts) => { ... });
400
+ ## 11. 原始 SDK 客户端
389
401
 
390
- // 形式二:对象(可指定分组和集群)
391
- naming.subscribe(
392
- { serviceName: 'user-service', groupName: 'PROD_GROUP', clusters: 'BJ' },
393
- (hosts) => { ... },
394
- );
402
+ 只有插件服务未覆盖 SDK 能力时才建议使用:
403
+
404
+ ```ts
405
+ import {
406
+ InjectNacosConfigClient,
407
+ InjectNacosNamingClient,
408
+ } from '@danqiusheng/nest-nacos';
409
+ import type {
410
+ NacosConfigClient,
411
+ NacosNamingClient,
412
+ } from 'nacos';
413
+
414
+ constructor(
415
+ @InjectNacosNamingClient()
416
+ private readonly namingClient: NacosNamingClient,
417
+ @InjectNacosConfigClient()
418
+ private readonly configClient: NacosConfigClient,
419
+ ) {}
395
420
  ```
396
421
 
397
- ---
398
-
399
- ## 11. API: NacosConfigService
400
-
401
- | 方法 | 参数 | 返回值 | 说明 |
402
- |------|------|--------|------|
403
- | `getConfig(dataId, group?)` | `string, string?` | `Promise<string>` | 获取配置内容(带缓存) |
404
- | `getConfigAsJson<T>(dataId, group?)` | `string, string?` | `Promise<T>` | 获取配置并解析为 JSON |
405
- | `publish(dataId, group, content)` | `string, string, string` | `Promise<boolean>` | 发布配置 |
406
- | `remove(dataId, group)` | `string, string` | `Promise<boolean>` | 删除配置 |
407
- | `subscribe(dataId, group, listener)` | `string, string, Function` | `void` | 订阅配置变更推送 |
408
- | `unSubscribe(dataId, group, listener?)` | `string, string, Function?` | `void` | 取消订阅 |
409
- | `getRawClient()` | 无 | `NacosConfigClient \| null` | 获取原始 SDK 客户端 |
410
-
411
- > **默认 group**:`getConfig()` 和 `getConfigAsJson()` 的 `group` 参数默认值为 `'DEFAULT_GROUP'`,如果配置在默认分组下可省略。
412
-
413
- ---
414
-
415
- ## 12. 配置项参考
416
-
417
- ### NacosModuleOptions
418
-
419
- | 字段 | 类型 | 必填 | 说明 |
420
- |------|------|------|------|
421
- | `naming` | `NacosNamingOptions` | 否 | Naming 服务发现配置,不传则不启用 |
422
- | `config` | `NacosConfigOptions` | 否 | Config 配置中心配置,不传则不启用 |
423
- | `instances` | `NacosInstanceOptions[]` | 否 | 启动时自动注册的服务实例列表 |
424
- | `subscribeConfigs` | `{ dataId, group }[]` | 否 | 启动时预订阅的配置项列表 |
425
-
426
- ### NacosNamingOptions
427
-
428
- | 字段 | 类型 | 默认值 | 说明 |
429
- |------|------|--------|------|
430
- | `serverList` | `string \| string[]` | - | Nacos 服务端地址 |
431
- | `namespace` | `string` | `'public'` | 命名空间 ID |
432
- | `transport` | `'grpc' \| 'http'` | `'grpc'` | 传输协议 |
433
- | `username` | `string` | - | 用户名 |
434
- | `password` | `string` | - | 密码 |
435
- | `ssl` | `boolean` | `false` | 是否启用 TLS/SSL |
436
- | `ak` | `string` | - | 阿里云 RAM AccessKey |
437
- | `sk` | `string` | - | 阿里云 RAM SecretKey |
438
- | `appName` | `string` | - | 应用名 |
439
-
440
- ### NacosConfigOptions
441
-
442
- | 字段 | 类型 | 默认值 | 说明 |
443
- |------|------|--------|------|
444
- | `serverAddr` | `string \| string[]` | - | Nacos 服务端地址 |
445
- | `namespace` | `string` | `'public'` | 命名空间 ID |
446
- | `transport` | `'grpc' \| 'http'` | `'grpc'` | 传输协议 |
447
- | `username` | `string` | - | 用户名 |
448
- | `password` | `string` | - | 密码 |
449
- | `ssl` | `boolean` | `false` | 是否启用 TLS/SSL |
450
- | `accessKey` | `string` | - | 阿里云 RAM AccessKey |
451
- | `secretKey` | `string` | - | 阿里云 RAM SecretKey |
452
- | `signatureRegionId` | `string` | - | v4 签名区域 ID |
453
-
454
- ### NacosInstanceOptions
455
-
456
- | 字段 | 类型 | 默认值 | 说明 |
457
- |------|------|--------|------|
458
- | `serviceName` | `string` | - | 服务名 |
459
- | `ip` | `string` | - | 实例 IP |
460
- | `port` | `number` | - | 实例端口 |
461
- | `weight` | `number` | `1.0` | 权重 |
462
- | `ephemeral` | `boolean` | `true` | 是否临时实例 |
463
- | `clusterName` | `string` | - | 集群名 |
464
- | `groupName` | `string` | `'DEFAULT_GROUP'` | 分组名 |
465
- | `metadata` | `Record<string, string>` | - | 元数据 |
466
-
467
- ---
422
+ 原始客户端由模块统一关闭,不要在业务代码中重复调用 `close()`。
423
+
424
+ ## 12. 兼容性
425
+
426
+ | 组件 | 支持范围 |
427
+ |---|---|
428
+ | NestJS | 10.x、11.x |
429
+ | Node.js | >= 16 |
430
+ | Nacos Node SDK | `nacos` 2.6.x |
431
+ | Nacos Server | 2.x(已对 2.5.3 做真实端到端验证) |
432
+ | Nacos Server 3.x | 不支持 |
433
+ | 传输协议 | Nacos HTTP OpenAPI;不支持 gRPC |
434
+
435
+ `nacos@2.6.x` 没有实现 Nacos 3.x 所需的 gRPC 协议。配置 `transport: 'grpc'` 时插件会立即抛出错误,不会静默回退造成假成功。
436
+
437
+ 插件本身不需要 Java。只有在本机运行 Nacos Server 时才需要 Java;NestJS 应用连接远程 Nacos 时只需要 Node.js。
468
438
 
469
439
  ## 13. 常见问题
470
440
 
471
- ### 只启用配置中心,不启用服务发现可以吗?
441
+ ### `getServerStatus()` 类型是 Promise
472
442
 
473
- 可以。`naming` `config` 都是可选的,只传 `config` 即可:
443
+ 必须使用 `await`:
474
444
 
475
- ```typescript
476
- NacosModule.forRoot({
477
- config: { serverAddr: '127.0.0.1:8848' },
478
- // 不传 naming,NacosNamingService 注入后客户端为 null
479
- })
445
+ ```ts
446
+ const status = await this.naming.getServerStatus();
480
447
  ```
481
448
 
482
- 此时 `NacosNamingService` 仍可注入,但调用其方法会抛出 `NacosNamingClient 未初始化` 错误。
449
+ ### 鉴权后 Naming 正常但 Config 失败
483
450
 
484
- ### 如何选择 gRPC 还是 HTTP 传输?
451
+ 使用顶层 `username/password` 可以同时传给两个客户端,避免重复配置遗漏:
485
452
 
486
- | 传输协议 | Nacos 2.x | Nacos 3.x | 推荐场景 |
487
- |----------|-----------|-----------|----------|
488
- | `grpc`(默认) | 支持 | 支持 | 推荐,实时推送,无需 UDP |
489
- | `http` | 支持 | 不支持 | 仅兼容旧版 Nacos 2.x 时使用 |
453
+ ```ts
454
+ NacosModule.forRoot({ serverAddr, username, password });
455
+ ```
490
456
 
491
- ### Nacos 3.x 连接失败怎么办?
457
+ ### public namespace 应该怎么写
492
458
 
493
- Nacos 3.x 已移除 HTTP API 支持,必须使用 gRPC 传输(默认)。确保:
459
+ 省略 `namespace` 或设置为 `public` 都可以。插件会按 Naming Config SDK 的不同要求正确归一化。
494
460
 
495
- - 未设置 `transport: 'http'`
496
- - Nacos Server 的 gRPC 端口(默认 9848,即 serverPort + 1000)已开放
497
- - 检查用户名密码是否正确
461
+ ### 应用无法退出
498
462
 
499
- ### 配置更新后业务代码没有生效?
463
+ 请通过 Nest 的 `app.close()` 或正常进程信号关闭。模块销毁时会注销实例、取消订阅并关闭两个 SDK 客户端。
500
464
 
501
- 确保通过 `subscribe()` 订阅了配置变更,并在回调中更新本地变量。`getConfig()` 返回的是缓存值,订阅后缓存会自动更新,但业务代码中引用的变量需要手动更新。
465
+ ### Nacos 3.x 为什么不能连接
502
466
 
503
- ### 如何获取原始 SDK 客户端?
467
+ 当前 Node SDK 没有 Nacos 3.x gRPC 实现。需要 Nacos 3.x 时不能通过修改 `transport` 参数解决,应等待或替换真正支持该协议的 SDK。
504
468
 
505
- 使用 `getRawClient()` 方法或 `@InjectNacosNamingClient()` / `@InjectNacosConfigClient()` 装饰器获取原始 `NacosNamingClient` / `NacosConfigClient` 实例,调用 SDK 未封装的高级 API。
469
+ ## 14. 验证
506
470
 
507
- ---
471
+ ```bash
472
+ npm ci
473
+ npm run build
474
+ npm test
475
+ ```
508
476
 
509
- *nest-nacos v1.0.0 · MIT License · 基于 nacos-sdk-nodejs v2.6.x*
477
+ 发布前还应针对真实 Nacos 2.x 执行端到端测试,并从服务端接口反查注册、配置发布和删除结果。