Skip to content

5.1 API管理

API 模块在 React 项目中主要负责与后端服务进行数据交互,它通过封装 HTTP 请求(如 get、post 等),实现前端组件对数据的获取(如获取列表、详情等)、提交(如创建、更新数据)、更新(如修改某些字段)以及删除等操作,并对请求和响应进行统一处理(如添加请求头、处理错误等),为前端组件提供稳定、高效的数据接口,从而实现动态页面的构建与更新。

kernelapi

单例模式实现

private static _instance: KernelApi;

public static getInstance(url: string = '/orginone/kernel/hub'): KernelApi {
  if (this._instance == null) {
    this._instance = new KernelApi(url);
  }
  return this._instance;
}

private constructor(url: string) {
  // 初始化逻辑
  this._storeHub = new StoreHub(url, 'txt');
  this._storeHub.start();
}
  • 功能:确保全局唯一实例,通过静态方法 getInstance() 获取实例

  • 特点:

  • 首次调用时初始化 WebSocket 连接

  • 默认连接地址为 /orginone/kernel/hub

  • 私有构造函数防止外部实例化

认证与令牌管理

// 访问令牌存取器
public get accessToken(): string {
  return sessionStorage.getItem('accessToken') || '';
}
private set accessToken(val: string) {
  sessionStorage.setItem('accessToken', val);
}

// 令牌验证方法
public async tokenAuth(): Promise<boolean> {
  if (this.accessToken?.length > 0) {
    const res = await this._storeHub.invoke('TokenAuth', this.accessToken);
    if (res.success) {
      this.user = res.data; // 更新当前用户信息
      return true;
    }
  }
  return false;
}
  • 功能:
  • 通过 sessionStorage 管理访问令牌
  • 自动验证令牌有效性并更新用户信息
  • 关联操作:所有需要认证的请求会自动携带有效令牌

核心通信方法

/**
 * 通用请求方法
 * @param req 包含 module/action/params 的请求对象
 * @returns 标准结果对象
 */
public async request(req: model.ReqestType): Promise<model.ResultType<any>> {
  return await this._storeHub.invoke('Request', req);
}

/**
 * 数据代理请求(带日志记录)
 */
public async dataProxy(req: model.DataProxyType): Promise<model.ResultType<any>> {
  const res = await this._storeHub.invoke('DataProxy', req);
  if (!res.success) {
    this.requestLogs.unshift({ 
      req: req, 
      res: res,
      date: new Date() 
    });
  }
  return res;
}
  • 参数结构:
interface ReqestType {
 module: string;  // 功能模块(如 'target'/'work')
action: string;  // 操作名称
params: any;     // 请求参数
}
  • 返回值:
interface ResultType<T> {
  success: boolean; // 是否成功
  code: number;     // 状态码
  msg: string;      // 消息说明
  data: T;          // 返回数据
}
  • request():通用请求方法,封装底层通信,接收模块名、操作名和参数。
  • dataProxy():数据代理请求,自动记录失败日志到 requestLogs 数组。

用户管理操作

用户管理相关接口示例,包含创建用户和查询用户信息。通过 target 模块标识用户管理功能。

/**
 * 创建用户
 * @param params 用户信息
 * @returns 创建结果
 */
public async createTarget(
  params: model.TargetModel
): Promise<model.ResultType<schema.XTarget>> {
  return this.request({
    module: 'target',
    action: 'CreateTarget',
    params: params
  });
}

/**
 * 查询用户信息
 * @param params 包含用户ID数组
 * @returns 分页用户数据
 */
public async queryTargetById(
  params: model.IdArrayModel
): Promise<model.ResultType<model.PageResult<schema.XTarget>>> {
  return this.request({
    module: 'target',
    action: 'QueryTargetById',
    params: params
  });
}
  • 参数实例:
// TargetModel 结构
{
  name: "新用户",
  code: "user001",
  teamId: "group1",
  //...其他字段
}

工作流管理

工作流管理接口示例,支持创建流程实例和处理审批任务。通过 work 模块标识工作流功能。

/**
 * 创建办事实例(启动流程)
 * @param params 包含流程定义信息
 * @returns 流程实例对象
 */
public async createWorkInstance(
  params: model.WorkInstanceModel
): Promise<model.ResultType<schema.XWorkInstance>> {
  return this.request({
    module: 'work',
    action: 'CreateWorkInstance',
    params: params
  });
}

/**
 * 处理审批任务
 * @param params 审批操作参数
 * @returns 处理结果
 */
public async approvalTask(
  params: model.ApprovalTaskReq
): Promise<model.ResultType<boolean>> {
  return this.request({
    module: 'work',
    action: 'ApprovalTask',
    params: params
  });
}

实时通信机制

/**
 * 订阅数据变更
 * @param flag 订阅标识 (格式:belongId-targetId-flag)
 * @param keys 关联键值
 * @param operation 回调函数
 */
public subscribe(
  flag: string,
  keys: string[],
  operation: (...args: any[]) => void
): void {
  flag = flag.toLowerCase();
  if (!this._subMethods[flag]) {
    this._subMethods[flag] = [];
  }
  this._subMethods[flag].push({ keys, operation });
}

/** 接收服务端推送 */
private _receive(res: model.ReceiveType) {
  switch (res.target) {
    case 'DataNotify':
      // 处理数据变更通知
      const data: model.DataNotityType = res.data;
      const flag = `${data.belongId}-${data.targetId}-${data.flag}`.toLowerCase();
      this._subMethods[flag]?.forEach(m => m.operation(data.data));
      break;
    case 'QrAuth':
      // 处理扫码登录
      this.accessToken = res.data;
      break;
    default:
      // 触发通用监听
      this._methods[res.target]?.forEach(m => m(res.data));
  }
}

*典型使用场景

// 订阅组织数据变更
kernelApi.subscribe('org123-storage-members', ['memberUpdate'], (data) => {
  console.log('成员变更:', data);
});
  • subscribe():订阅数据变更,flag 格式为 belongId-targetId-flag
  • _receive():接收服务端推送,自动触发订阅回调。

连接状态管理

/**
 * 实时获取连接状态变化
 * @param callback 状态回调函数
 */
public async onConnectedChanged(callback: (res: boolean) => void) {
  callback(this._storeHub.isConnected);
  this._storeHub.onDisconnected(() => callback(false));
  this._storeHub.onConnected(() => callback(true));
}

// 获取当前连接状态
public get isOnline(): boolean {
  return this._storeHub.isConnected;
}
  • onConnectedChanged():监听连接状态变化,实时返回在线状态。
  • isOnline:直接获取当前连接状态。

文件操作接口

通过 Bucket 模块操作文件存储,支持上传/下载等操作,参数包含操作类型、文件路径等。

/**
 * 桶操作(文件上传/下载)
 * @param data 操作参数
 * @returns 操作结果
 */
public async bucketOperate<T>(
  data: model.BucketOperateModel
): Promise<model.ResultType<T>> {
  return this.dataProxy({
    module: 'Bucket',
    action: 'Operate',
    params: data
  });
}

错误处理机制

自动记录失败的请求信息到 requestLogs 数组,包含请求参数、响应结果和时间戳,便于调试。

public recorder: boolean = false;
public requestLogs: model.RequestRecord[] = [];

// 请求失败时自动记录
if (res.success !== true) {
  this.requestLogs.unshift({
    req: req,
    res: res,
    date: new Date()
  });
}
  • 日志结构
interface RequestRecord {
  req: any;          // 原始请求
  res: ResultType<any>; // 响应结果
  date: Date;        // 发生时间
}

StoreHub

StoreHub实现为上层业务模块(如KernelApi)提供了稳定的实时通信基础能力,其实现的主要功能如下 (1)双协议支持:同时兼容 JSON 和自定义文本协议 (2)自动恢复:断线后按配置策略自动重连 (3)错误隔离:异常捕获与标准化错误响应 (4)性能优化:心跳机制保持连接活性 (5)统一认证:自动管理访问令牌的存储和传递

连接配置与初始化

constructor(url: string, protocol = 'json', timeout = 10000, interval = 2000) {
  // 协议配置
  let hubProtocol: signalR.IHubProtocol = new signalR.JsonHubProtocol();
  if (protocol == 'txt') {
    hubProtocol = new TxtHubProtocol(); // 自定义文本协议
  }

  // 连接构建
  this._connection = new signalR.HubConnectionBuilder()
    .withUrl(url)
    .withHubProtocol(hubProtocol)
    .build();

  // 超时与心跳配置
  this._connection.serverTimeoutInMilliseconds = timeout; // 10秒超时
  this._connection.keepAliveIntervalInMilliseconds = interval; // 2秒心跳
}
  • 支持 JSON 和自定义 TXT 协议
  • 设置服务端响应超时时间和心跳间隔
  • 默认配置:10秒超时检测、2秒心跳包

连接生命周期管理

// 自动重连机制
this._connection.onclose((err) => {
  if (this._isStarted) {
    logger.warn(`连接断开,${this._timeout}ms后重试`);
    setTimeout(() => this._starting(), this._timeout); // 超时后自动重连
  }
});

// 手动启动连接
public start(): void {
  if (!this._isStarted) {
    this._isStarted = true;
    this._starting(); // 触发连接流程
  }
}

// 强制重启连接
public async restart(): Promise<void> {
  await this._connection.stop();
  setTimeout(() => this.start(), 1000); // 1秒后重新连接
}
  • 断线后自动按配置时间重试
  • 提供手动重启方法应对网络波动
  • 状态管理通过 _isStarted 标志位控制

双向通信接口

/**
 * 调用服务端方法(核心方法)
 * @param methodName 方法名称
 * @param args 参数列表
 * @returns 标准化响应结果
 */
public invoke(methodName: string, ...args: any[]): Promise<ResultType<any>> {
  return new Promise((resolve) => {
    if (this.isConnected) {
      // WebSocket调用
      this._connection.invoke(methodName, ...args)
        .then(res => this._handleResponse(res))
        .catch(err => this._handleError(err));
    } else {
      // HTTP回退调用
      this.restRequest('post', `/orginone/kernel/rest/${methodName.toLowerCase()}`, args[0])
        .then(res => resolve(res));
    }
  });
}

// 特殊处理临时令牌请求
if (methodName === 'createTemporaryToken') {
  this.restRequest('get', '/orginone/kernel/rest/createTemporaryToken', undefined)
    .then(success)
    .catch(error);
}
  • 优先使用 WebSocket 通信
  • 当连接断开时自动降级到 HTTP REST 调用
  • 统一返回 ResultType 标准化响应结构
  • 特殊处理 createTemporaryToken 的 GET 请求

HTTP回退机制

public async restRequest(method: string, url: string, args: any): Promise<ResultType<any>> {
  const res = await this._http.send({
    url: url,
    method: method,
    content: JSON.stringify(args),
    headers: { Authorization: this.accessToken } // 自动携带令牌
  });
  
  // 处理响应
  if (res.statusCode === 200) {
    return JSON.parse(res.content.replace(/"_id":/gm, '"id":')); // 特殊字段转换
  }
  return badRequest(res.statusText, res.statusCode);
}
  • 当 WebSocket 不可用时自动切换 HTTP
  • 统一处理授权头部
  • 自动转换 MongoDB 的 _id 字段为 id
  • 30秒请求超时控制

事件处理系统

  • 连接状态监听
// 注册连接成功回调
public onConnected(callback: () => void): void {
  this._connectedCallbacks.push(callback);
}

// 注册断开连接回调
public onDisconnected(callback: (err: Error | undefined) => void): void {
  this._disconnectedCallbacks.push(callback);
}

// 实际触发逻辑
private async _starting() {
  this._connection.start()
    .then(() => this._connectedCallbacks.forEach(c => c()))
    .catch(err => this._disconnectedCallbacks.forEach(c => c(err)));
}
  • 服务端消息监听
public on(methodName: string, newMethod: (...args: any[]) => any): void {
  this._connection.on(methodName, newMethod); // 原生SignalR监听
}

错误处理机制

const error = (reason: any) => {
  let msg = '请求异常';
  if (reason?.Error) msg += ',' + reason.Error();
  resolve(badRequest(msg)); // 返回标准错误对象
};

// 在invoke方法中
.catch(error);

// 错误响应结构
interface ResultType<T> {
  success: boolean;
  code: number; // 401=未授权
  msg: string;
  data?: T;
}
  • 自动捕获通信异常
  • 401状态自动触发未授权提示
  • 过滤非关键错误日志(如"不在线"提示)

云原生应用研究院版权所有