Nacos Node.js SDK

repository·master·Indexed 43 days ago

https://github.com/nacos-group/nacos-sdk-nodejs

A Node.js SDK for Nacos providing service discovery (naming) and dynamic configuration management. It includes the NacosNamingClient for registering and querying service instances and the NacosConfigClient for CRUD operations and real-time subscriptions to configuration changes. Supports gRPC transport for Nacos 2.x and 3.x, and HTTP REST API for Nacos 2.x.

Tokens
15.3K
Snippets
42
Records
52
Agent score
53%

What's inside Nacos

  1. Use custom credential providers for RoleArn or OIDC/RRSA

    master

    If you need to use advanced authentication like RoleArn (AssumeRole), OIDC/RRSA, or KMS secret rotation, you must provide an asynchronous function to aliyunCredentialsProvider or alibabaCloudCredentialsProvider. This function is responsible for fetching temporary credentials from Aliyun STS or another source. The SDK will consume the returned AccessKeyId, AccessKeySecret, and SecurityToken to sign requests.

    Implementation Pattern

    The provider should ideally handle credential caching and refreshing based on the Expiration field returned by the STS service to avoid unnecessary network calls.

    const clientOptions = {
      serverAddr: '127.0.0.1:8848',
      aliyunCredentialsProvider: async () => {
        return {
          AccessKeyId: 'AccessKeyId',
          AccessKeySecret: 'AccessKeySecret',
          SecurityToken: 'SecurityToken',
        };
      },
    };
  2. Understand Nacos SDK transport protocols and compatibility

    master

    The SDK supports two transport protocols, but their availability depends on your Nacos server version:

    • grpc (default): Uses gRPC + Protobuf. Supported by Nacos 2.x and 3.x. It provides real-time bidirectional streaming, server push, and automatic reconnection with exponential backoff. It does not require UDP ports.
    • http: Uses HTTP REST API. Supported by Nacos 2.x only. It uses long-polling and UDP push.

    Important: Nacos 3.x has removed HTTP API support. When connecting to Nacos 3.x, grpc is the only available transport.

    | Transport | Protocol | Server Version | Description |
    |---|---|---|---|
    | `grpc` (default) | gRPC + Protobuf | Nacos 2.x / 3.x | Bidirectional streaming, server push, connection-based heartbeat |
    | `http` | HTTP REST API | Nacos 2.x only | Long-polling, UDP push, explicit heartbeat |
  3. Configure Aliyun RAM Authentication

    master

    Starting from version 2.6.3, the SDK supports multiple methods for Aliyun RAM identity configuration. All methods resolve to AccessKeyId, AccessKeySecret, and an optional SecurityToken. The SDK then generates the necessary Nacos authentication fields for Config and Naming clients.

    Supported Methods

    1. Legacy AK/SK: Use accessKey/secretKey for NacosConfigClient or ak/sk for NacosNamingClient.
    2. Static STS Credentials: Provide alibabaCloudAccessKeyId, alibabaCloudAccessKeySecret, and alibabaCloudSecurityToken in the client options.
    3. Environment Variables: Set ALIBABA_CLOUD_ACCESS_KEY_ID, ALIBABA_CLOUD_ACCESS_KEY_SECRET, and ALIBABA_CLOUD_SECURITY_TOKEN.
    4. Credentials URI: Provide an alibabaCloudCredentialsUri pointing to a JSON endpoint returning credentials.
    5. Security Credentials JSON: Provide a stringified JSON object via securityCredentials (compatible with Java client keys).
    6. Security Credentials URL & ECS RAM Role: Use securityCredentialsUrl (with cacheSecurityCredentials and timeToRefreshInMillisecond) or ramRoleName for ECS environments.
    7. Custom Providers: For RoleArn, OIDC/RRSA, or KMS rotation, implement an aliyunCredentialsProvider or alibabaCloudCredentialsProvider function that returns the credential object.
    // Example: Static STS credentials
    const clientOptions = {
      serverAddr: '127.0.0.1:8848',
      alibabaCloudAccessKeyId: 'AccessKeyId',
      alibabaCloudAccessKeySecret: 'AccessKeySecret',
      alibabaCloudSecurityToken: 'SecurityToken',
    };
  4. Use NacosNamingClient for Service Discovery

    master

    The NacosNamingClient allows you to register service instances, query them, and subscribe to changes.

    Basic Usage Example

    const { NacosNamingClient } = require('nacos');
    
    const client = new NacosNamingClient({
      logger: console,
      serverList: '127.0.0.1:8848',
      namespace: 'public',
    });
    await client.ready();
    
    const serviceName = 'nodejs.test.domain';
    
    // Register an instance
    await client.registerInstance(serviceName, {
      ip: '1.1.1.1',
      port: 8080,
    });
    
    // Subscribe to instance changes (push notification)
    client.subscribe(serviceName, hosts => {
      console.log(hosts);
    });
    
    // Query all instances
    const hosts = await client.getAllInstances(serviceName);
    
    // Select healthy instances only
    const healthy = await client.selectInstances(serviceName);
    
    // Deregister instance
    await client.deregisterInstance(serviceName, {
      ip: '1.1.1.1',
      port: 8080,
    });
    const { NacosNamingClient } = require('nacos');
    
    const client = new NacosNamingClient({
      logger: console,
      serverList: '127.0.0.1:8848',
      namespace: 'public',
    });
    await client.ready();
    
    const serviceName = 'nodejs.test.domain';
    
    // register instance
    await client.registerInstance(serviceName, {
      ip: '1.1.1.1',
      port: 8080,
    });
    
    // subscribe to instance changes (push notification)
    client.subscribe(serviceName, hosts => {
      console.log(hosts);
    });
    
    // query all instances
    const hosts = await client.getAllInstances(serviceName);
    console.log(hosts);
    
    // select healthy instances only
    const healthy = await client.selectInstances(serviceName);
    console.log(healthy);
    
    // deregister instance
    await client.deregisterInstance(serviceName, {
      ip: '1.1.1.1',
      port: 8080,
    });
  5. Initialize NacosConfigClient

    master

    To use the Nacos configuration service, instantiate NacosConfigClient. You can use two different connection modes:

    1. Addressing Mode (寻址模式): Used for cloud environments (like Aliyun ACM). Requires endpoint, namespace, accessKey, and secretKey.
    2. Direct Connection Mode (直连模式): Used for connecting directly to a Nacos server instance. Requires serverAddr (IP and port).

    Common options include requestTimeout (defaults to 6000ms).

    import {NacosConfigClient} from 'nacos'; // TypeScript
    // OR
    const {NacosConfigClient} = require('nacos'); // JavaScript
    
    // Addressing Mode
    const configClient = new NacosConfigClient({
      endpoint: 'acm.aliyun.com',
      namespace: '***************',
      accessKey: '***************',
      secretKey: '***************',
      requestTimeout: 6000,
    });
    
    // Direct Connection Mode
    const configClient = new NacosConfigClient({
      serverAddr: '127.0.0.1:8848',
    });
  6. Use NacosConfigClient for Configuration Management

    master

    The NacosConfigClient allows you to manage remote configurations, including publishing, retrieving, and subscribing to changes.

    Basic Usage Example

    const { NacosConfigClient } = require('nacos');
    
    const configClient = new NacosConfigClient({
      serverAddr: '127.0.0.1:8848',
      namespace: 'public',
    });
    await configClient.ready();
    
    // Publish config
    await configClient.publishSingle('test', 'DEFAULT_GROUP', 'hello=world');
    
    // Get config
    const content = await configClient.getConfig('test', 'DEFAULT_GROUP');
    
    // Subscribe to config changes
    configClient.subscribe({ dataId: 'test', group: 'DEFAULT_GROUP' }, content => {
      console.log('config changed:', content);
    });
    
    // Remove config
    await configClient.remove('test', 'DEFAULT_GROUP');
    const { NacosConfigClient } = require('nacos');
    
    const configClient = new NacosConfigClient({
      serverAddr: '127.0.0.1:8848',
      namespace: 'public',
    });
    await configClient.ready();
    
    // publish config
    await configClient.publishSingle('test', 'DEFAULT_GROUP', 'hello=world');
    
    // publish config with CAS (compare-and-set):
    // succeeds only when the md5 of the current server-side config equals casMd5
    const crypto = require('crypto');
    const currentContent = await configClient.getConfig('test', 'DEFAULT_GROUP');
    const casMd5 = crypto.createHash('md5').update(currentContent || '').digest('hex');
    const published = await configClient.publishConfigCas('test', 'DEFAULT_GROUP', 'hello=nacos', casMd5);
    console.log('cas publish:', published); // false when casMd5 mismatched
    
    // get config
    const content = await configClient.getConfig('test', 'DEFAULT_GROUP');
    console.log('content:', content);
    
    // subscribe to config changes (push notification)
    configClient.subscribe({ dataId: 'test', group: 'DEFAULT_GROUP' }, content => {
      console.log('config changed:', content);
    });
    
    // remove config
    await configClient.remove('test', 'DEFAULT_GROUP');
  7. Configure NacosNamingClient options

    master

    Options for initializing NacosNamingClient:

    OptionTypeDefaultDescription
    loggerObjectrequiredLogger instance
    serverListString/String[]requiredNacos server addresses, e.g. '127.0.0.1:8848'
    namespaceString'public'Namespace ID
    transportString'grpc'Transport protocol: 'grpc' or 'http'
    usernameStringAuthentication username
    passwordStringAuthentication password
    sslBooleanfalseUse TLS/SSL
  8. Configure NacosConfigClient options

    master

    Options for initializing NacosConfigClient:

    OptionTypeDefaultDescription
    serverAddrString/String[]requiredNacos server addresses
    namespaceString'public'Namespace ID
    transportString'grpc'Transport protocol: 'grpc' or 'http'
    usernameStringAuthentication username
    passwordStringAuthentication password
    sslBooleanfalseUse TLS/SSL
  9. Use Service Discovery with NacosNamingClient

    master

    To use service discovery, instantiate NacosNamingClient with a serverList and namespace. You must call await client.ready() before performing operations. The client allows you to register service instances, subscribe to changes in service instances, and deregister instances.

    'use strict';
    
    const NacosNamingClient = require('nacos').NacosNamingClient;
    const logger = console;
    
    const client = new NacosNamingClient({
      logger,
      serverList: '127.0.0.1:8848', // replace to real nacos serverList
      namespace: 'public',
    });
    await client.ready();
    
    const serviceName = 'nodejs.test.domain';
    
    // registry instance
    await client.registerInstance(serviceName, {
      ip: '1.1.1.1',
      port: 8080,
    });
    await client.registerInstance(serviceName, {
      ip: '2.2.2.2',
      port: 8080,
    });
    
    // subscribe instance
    client.subscribe(serviceName, hosts => {
      console.log(hosts);
    });
    
    // deregister instance
    await client.deregisterInstance(serviceName, {
      ip: '1.1.1.1',
      port: 8080,
    });
  10. Publish configuration with CAS (Compare-and-Set)

    master

    To prevent overwriting changes made by other clients, use publishConfigCas. This method succeeds only if the MD5 hash of the current server-side configuration matches the casMd5 you provide.

    const crypto = require('crypto');
    
    // 1. Get current content
    const currentContent = await configClient.getConfig('test', 'DEFAULT_GROUP');
    
    // 2. Calculate MD5 of current content
    const casMd5 = crypto.createHash('md5').update(currentContent || '').digest('hex');
    
    // 3. Attempt to publish with the MD5
    const published = await configClient.publishConfigCas('test', 'DEFAULT_GROUP', 'new_content', casMd5);
    
    if (published) {
      console.log('Update successful');
    } else {
      console.log('Update failed: MD5 mismatch (someone else updated the config)');
    }
    const crypto = require('crypto');
    const currentContent = await configClient.getConfig('test', 'DEFAULT_GROUP');
    const casMd5 = crypto.createHash('md5').update(currentContent || '').digest('hex');
    const published = await configClient.publishConfigCas('test', 'DEFAULT_GROUP', 'hello=nacos', casMd5);
    console.log('cas publish:', published); // false when casMd5 mismatched