

这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段，并于 2023 年 6 月 1 日终止支持。

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 配置 CDK 工具包消息和交互
<a name="toolkit-library-configure-messages"></a>

AWS CDK 工具包库提供 ` [IIoHost](https://docs.aws.amazon.com/cdk/api/toolkit-lib/Package/toolkit-lib/Interface/IIoHost/) ` 接口，用于自定义 CDK 操作期间消息和交互的处理方式，使您能够控制部署进度、错误消息和用户提示的显示，从而更好地与应用程序的用户体验进行集成。

在执行部署或合成等操作之前，您需要了解 CDK 工具包如何与用户通信。`IIoHost` 接口充当 CDK 工具包和您的应用程序之间的通信渠道，处理传出的消息和传入的用户响应。

当 CDK 工具包运行操作时，主要通过两种机制进行通信：
+  **消息**：通知您操作进度的信息性输出（例如“开始部署”或“已创建资源”）。
+  **请求**：需要输入或确认的决策点（例如“您是否要部署这些更改？”），让您有机会提供事先不知道需要的信息。

## 使用 `IIoHost` 接口
<a name="toolkit-library-configure-messages-iiohost"></a>

`IIoHost` 接口包含两个主要方法：

1.  `notify`：处理单向信息性消息。

1.  `requestResponse`：处理需要响应的交互式请求。

```
import { IoMessage, IoRequest } from '@aws-cdk/toolkit-lib';

interface IIoHost {
  // Handle informational messages
  notify(message: IoMessage): Promise<void>;

  // Handle requests that need responses
  requestResponse(request: IoRequest): Promise<any>;
}
```

## 消息级别和请求类型
<a name="toolkit-library-configure-messages-levels"></a>

CDK 工具包会生成多种类型的消息和请求：

### 消息级别
<a name="_message_levels"></a>
+  **调试**：故障排除的详细消息。
+  **错误**：可能影响操作的错误消息。
+  **信息**：一般信息性消息。
+  **结果** - 操作的主要消息。
+  **跟踪**：非常详细的执行流程信息。
+  **警告**：不会阻止操作的警告消息。

有关完整列表，请参阅《AWS CDK 工具包库 API 参考》**中的 [IoMessages Registry](https://docs.aws.amazon.com/cdk/api/toolkit-lib/message-registry/)。

### 请求类型
<a name="_request_types"></a>

当需要用户输入或确认时，CDK 工具包会发送请求。这些是允许响应的特殊消息。如果没有提供响应，工具包将使用可用的默认响应。

## 基本 `IIoHost` 实施
<a name="toolkit-library-configure-messages-basic"></a>

下面是一个实现自定义 io 主机的简单示例：

```
import { Toolkit } from '@aws-cdk/toolkit-lib';

// Create a toolkit with custom message handling
const toolkit = new Toolkit({
  ioHost: {
    // Implementing the IIoHost interface
    // Handle informational messages
    notify: async function (msg) {
      // Example: Handle different message levels appropriately
      switch (msg.level) {
        case 'error':
          console.error(`[${msg.time}] ERROR: ${msg.message}`);
          break;
        case 'warning':
          console.warn(`[${msg.time}] WARNING: ${msg.message}`);
          break;
        case 'info':
          console.info(`[${msg.time}] INFO: ${msg.message}`);
          break;
        case 'debug':
          console.debug(`[${msg.time}] DEBUG: ${msg.message}`);
          break;
        case 'trace':
          console.debug(`[${msg.time}] TRACE: ${msg.message}`);
          break;
        default:
          console.log(`[${msg.time}] ${msg.level}: ${msg.message}`);
      }
    },

    // Handle requests that need responses
    requestResponse: async function (msg) {
      // Example: Log the request and use default response
      console.log(`Request: ${msg.message}, using default: ${msg.defaultResponse}`);
      return msg.defaultResponse;

      // Or implement custom logic to provide responses
      // if (msg.type === 'deploy') {
      //   return promptUserForDeployment(msg);
      // }
    }
  } as IIoHost // Explicitly cast to IIoHost interface
});
```

CDK 工具包会等待每次调用完成，从而允许您在处理消息时执行异步操作（例如，HTTP 请求或用户提示）。

## 默认 `IIoHost` 行为
<a name="toolkit-library-configure-messages-iiohost-default"></a>

如果您不提供自定义 io 主机，CDK 工具包库将使用默认非交互式实现：
+ 消息的控制台输出（对不同消息类型使用适当的颜色）。
+ 完全非交互式，不提示用户输入。
+ 尽可能自动使用默认响应（相当于对提示回答“是”）。
+ 当需要输入但没有默认响应可用时失败。

此默认行为适用于无人值守的操作，但不适用于交互式命令行应用程序。对于需要用户交互的命令行应用程序，您需要实现自定义 io 主机。自定义实现还可用于与日志记录系统、UI 或其他专用环境集成。

## 高级 io 主机实现
<a name="toolkit-library-configure-messages-advanced"></a>

对于更复杂的场景，我们建议以扩展 `NonInteractiveIoHost` 类作为起点。这种方法允许您利用现有的非交互式实现，同时仅自定义您需要更改的特定行为。

下面是扩展基本实现的自定义 io 主机的示例：

```
import { NonInteractiveIoHost } from '@aws-cdk/toolkit-lib';

class MyCustomIoHost extends NonInteractiveIoHost {
  // Override only the methods you need to customize

  // Example: Custom implementation for notify
  public async notify(msg: IoMessage<unknown>): Promise<void> {
    // Add custom notification handling logic
    if (msg.level === 'error') {
      console.error(`ERROR: ${msg.message}`);
      // Optionally log to a service or notify a monitoring system
      await this.logToMonitoringService(msg);
    } else {
      await super.notify(msg);
    }
  }

  // Example: Custom implementation for requestResponse
  public async requestResponse<T, U>(request: IoRequest<T, U>): Promise<U> {
    // Implement custom request handling
    console.log(`Received request: ${request.message}`);
    return request.defaultResponse;
  }

  private async logToMonitoringService(msg: IoMessage<unknown>): Promise<void> {
    // Implementation for monitoring service integration
    console.log(`Logging to monitoring service: ${msg.level} - ${msg.message}`);
  }
}
```

这种方法比从头开始实现整个 `IIoHost` 接口更易于维护，因为您只需要覆盖需要自定义行为的特定方法即可。

## 与不同的环境集成
<a name="toolkit-library-configure-messages-integration"></a>

### Web 应用程序集成
<a name="_web_application_integration"></a>

```
import { Toolkit } from '@aws-cdk/toolkit-lib';

// Example for integrating with a web application
const toolkit = new Toolkit({
  ioHost: {
    notify: async function (msg) {
      // Send message to frontend via WebSocket
      webSocketServer.send(JSON.stringify({
        type: 'cdk-notification',
        messageLevel: msg.level,
        message: msg.message,
        time: msg.time
      }));
    },

    requestResponse: async function (msg) {
      // Create a promise that will be resolved when the user responds
      return new Promise((resolve) => {
        const requestId = generateUniqueId();

        // Store the resolver function
        pendingRequests[requestId] = resolve;

        // Send request to frontend
        webSocketServer.send(JSON.stringify({
          type: 'cdk-request',
          requestId: requestId,
          requestType: msg.type,
          message: msg.message,
          defaultResponse: msg.defaultResponse
        }));

        // Frontend would call an API endpoint with the response,
        // which would then call pendingRequests[requestId](response)
      });
    }
  } as IIoHost // Explicitly cast to IIoHost interface
});
```

### CI/CD 环境集成
<a name="_cicd_environment_integration"></a>

```
import { Toolkit } from '@aws-cdk/toolkit-lib';

// Example for CI/CD environments (non-interactive)
const toolkit = new Toolkit({
  ioHost: {
    notify: async function (msg) {
      // Log all messages with appropriate level
      switch (msg.level) {
        case 'error':
          console.error(msg.message);
          break;
        case 'warning':
          console.warn(msg.message);
          break;
        default:
          console.log(msg.message);
      }
    },

    requestResponse: async function (msg) {
      // In CI/CD, always use default responses or predefined answers
      console.log(`Auto-responding to request: ${msg.message} with ${msg.defaultResponse}`);
      return msg.defaultResponse;
    }
  } as IIoHost // Explicitly cast to IIoHost interface
});
```

## io 主机实现的最佳实践
<a name="toolkit-library-configure-messages-best-practices"></a>

在实现自定义 io 主机时，请考虑下面的最佳实践：
+  **错误处理**：在 io 主机方法中实施强大的错误处理，以防止故障影响 CDK 操作。
+  **超时**：考虑对用户交互实施超时，以防止无限期等待。
+  **日志记录**：将重要消息存储在日志中以便进行故障排除，尤其是在非交互式环境中。
+  **默认响应**：为无法进行用户交互的自动化环境提供合理的默认响应。
+  **进度指示**：对于长时间运行的操作，提供明确的进度指示器以改善用户体验。

以下示例通过实现具有错误处理、用户交互超时和适当日志记录的自定义 io 主机来演示这些最佳实践。此实现适用于需要在用户响应和可靠操作之间取得平衡的交互式应用程序：

```
import { Toolkit } from '@aws-cdk/toolkit-lib';

// Example with error handling and timeouts
const toolkit = new Toolkit({
  ioHost: {
    notify: async function (msg) {
      try {
        console.log(`[${msg.time}] ${msg.level}: ${msg.message}`);
        // Additional logging or UI updates
      } catch (error) {
        // Ensure errors in notification handling don't break the CDK operation
        console.error("Error handling notification:", error);
      }
    },

    requestResponse: async function (msg) {
      try {
        // Implement timeout for user response
        const response = await Promise.race([
          getUserResponse(msg),
          new Promise(resolve => setTimeout(() => resolve(msg.defaultResponse), 60000))
        ]);
        return response;
      } catch (error) {
        console.error("Error handling request:", error);
        return msg.defaultResponse;
      }
    }
  } as IIoHost // Explicitly cast to IIoHost interface
});
```

## 故障排除
<a name="toolkit-library-configure-messages-troubleshooting"></a>

实现自定义 io 主机时的注意事项：
+  **未处理的承诺拒绝**：确保所有异步操作都使用 try/catch 块正确处理。
+  **无限等待**：为所有用户交互实施超时，以防止应用程序挂起。
+  **缺少消息级别**：准备好处理未来 CDK 版本中可能新增的消息级别。
+  **响应不一致**：确保您的 requestResponse 实现以预期格式返回值。

以下示例演示了一种可靠的处理消息级别的方法，包括正常处理可能在未来的 CDK 版本中引入的未知消息类型。此实现可确保 io 主机与 CDK 更新保持兼容，同时保持正确的日志记录：

```
import { Toolkit } from '@aws-cdk/toolkit-lib';

// Example of handling unknown message levels
const toolkit = new Toolkit({
  ioHost: {
    notify: async function (msg) {
      // Handle known levels
      const knownLevels = ['info', 'warning', 'error', 'debug', 'trace', 'status'];

      if (knownLevels.includes(msg.level)) {
        // Handle known level
        handleKnownMessageLevel(msg);
      } else {
        // Handle unknown level as info
        console.log(`Unknown message level "${msg.level}": ${msg.message}`);
      }
    },

    requestResponse: async function (msg) {
      // Default implementation
      return msg.defaultResponse;
    }
  } as IIoHost // Explicitly cast to IIoHost interface
});
```