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状态自动触发未授权提示
- 过滤非关键错误日志(如"不在线"提示)