组件间通信


在一个由多个组件组成的 Blocklet 应用中,使它们能够安全可靠地相互通信至关重要。Blocklet SDK 提供了一个高级实用工具 component.call,专为此目的而设计。该方法通过处理服务发现、请求签名和自动重试,简化了组件间的 API 调用。

这种方法比直接发起 HTTP 请求更健壮,因为它抽象了底层环境的复杂性,例如动态端口和 Docker 网络,同时确保所有通信都经过身份验证。

发起安全 API 调用#

组件间通信的主要方法是 component.call。它作为 HTTP 客户端(axios)的包装器,但会自动注入必要的身份验证标头,以验证调用组件的身份。

基本用法#

这是一个基本示例,演示一个组件如何调用名为“user-service”的另一个组件上的 API 端点。

Calling another component

import component from '@blocklet/sdk/component';

async function getUserProfile(userId) {
  try {
    const response = await component.call({
      name: 'user-service', // 目标组件的名称、DID 或标题
      method: 'GET',
      path: `/api/users/${userId}`,
    });

    console.log('用户个人资料:', response.data);
    return response.data;
  } catch (error) {
    console.error('调用 user-service 失败:', error.message);
  }
}

工作原理#

component.call 函数通过几个关键步骤简化了通信过程:

  1. 服务发现:它在应用程序的组件注册表中查找目标组件(例如,“user-service”),以找到其当前位置和元数据。
  2. 端点解析:它构造正确的内部 URL 以访问该组件,自动处理 Docker 容器网络等复杂性。
  3. 请求签名:在发送请求之前,它会自动添加特殊的 x-component-* 标头。这些标头包含使用调用组件的密钥生成的签名,以证明其身份。
  4. API 调用:它使用配置的方法、路径和数据执行 HTTP 请求。
  5. 自动重试:如果请求因暂时的服务器错误(例如,5xx 状态码)而失败,它将自动以递增的延迟(指数退避)重试几次请求。

此流程确保通信既可靠又安全。接收组件可以使用 session 中间件 来验证签名并授权请求。

Component-to-Component Communication

call 参数#

component.call 函数接受一个包含以下属性的选项对象:

name
string
required
要调用的目标组件的名称、标题或 DID。
method
string
default:POST
请求的 HTTP 方法(例如,'GET'、'POST'、'PUT'、'DELETE')。
path
string
required
目标组件上的 API 路径(例如,'/api/v1/resource')。
data
any

请求体,通常与 POSTPUTPATCH 方法一起使用。

params
any
要附加到请求 URL 的 URL 查询参数。
headers
object
要与请求一起发送的自定义标头对象。
timeout
number
请求超时时间,单位为毫秒。
responseType
string
服务器将响应的数据类型。例如,'stream'。

返回值#

该函数返回一个 Promise,它会解析为一个 AxiosResponse 对象,其中包含 datastatusheaders 等属性。

高级用法#

自定义重试行为#

你可以通过向 component.call 传递第二个参数来自定义自动重试逻辑。这对于适应端点的特定可靠性需求非常有用。

Custom Retry Options

import component from '@blocklet/sdk/component';

const callOptions = {
  name: 'data-processor',
  method: 'POST',
  path: '/api/process',
  data: { job: 'some-long-job' },
};

const retryOptions = {
  retries: 5,       // 总共尝试 5 次
  minTimeout: 1000, // 两次重试之间至少等待 1 秒
  factor: 2,        // 每次失败后等待时间加倍
};

async function processData() {
  const response = await component.call(callOptions, retryOptions);
  return response.data;
}

retryOptions 对象可以具有以下属性:

retries
number
default:3
要进行的总尝试次数。
factor
number
default:2
用于退避的指数因子。
minTimeout
number
default:500
两次重试之间的最小超时时间,单位为毫秒。
maxTimeout
number
default:5000
两次重试之间的最大超时时间,单位为毫秒。
randomize
boolean
default:true
是否随机化超时时间。
onFailedAttempt
function
每次失败尝试时调用的回调函数。

处理流式响应#

对于返回流的端点(例如,下载大文件),你可以设置 responseType: 'stream'。这允许你在数据到达时进行处理,而无需将整个响应缓冲在内存中。

Streaming a File

import fs from 'fs';
import component from '@blocklet/sdk/component';

async function downloadBackup() {
  const response = await component.call({
    name: 'backup-service',
    method: 'GET',
    path: '/api/export',
    responseType: 'stream',
  });

  const writer = fs.createWriteStream('backup.zip');
  response.data.pipe(writer);

  return new Promise((resolve, reject) => {
    writer.on('finish', resolve);
    writer.on('error', reject);
  });
}

通过使用 component.call,你可以轻松构建健壮且安全的多组件应用程序。接下来,你需要学习如何通过验证这些传入的调用来保护你的组件的 API 端点。详情请参阅 Session 中间件 指南。