@iocore/micro-ws-agent v1.1.6
@iocore/micro-ws-agent
IoCore 微服务 WebSocket Agent (客户端/服务端)。
该模块允许你构建一个 IoCore 微服务,该服务通过 WebSocket 与注册中心 (@iocore/micro-ws-registry) 通信以实现服务发现,并能处理来自其他 Agent 或客户端的请求。
支持两种主要的服务模式:
- WebSocket Service (
Service): 处理纯粹的 WebSocket 消息,适用于 RPC 风格的调用。 - HTTP-like Controller (
Controller): 模拟 HTTP 请求/响应模式,通过 WebSocket 传输,支持中间件和类似 Koa 的上下文 (Context)。
安装
npm install @iocore/micro-ws-agent @iocore/logger @iocore/micro-ws @iocore/component detect-port retry --save
# or
yarn add @iocore/micro-ws-agent @iocore/logger @iocore/micro-ws @iocore/component detect-port retry依赖
@iocore/logger@iocore/micro-ws@iocore/componentdetect-port(用于自动检测可用端口)retry(用于注册中心重连)
配置
通过环境变量 IOCORE_MICRO_WEBSOCKET_AGENT_CONFIGS 配置 Agent。该变量应包含一个 JSON 字符串。
export type IOCORE_MICRO_WEBSOCKET_AGENT_CONFIGS = {
registry: string; // 注册中心地址 (例如 'ws://localhost:8427')
namespace: string; // 当前服务的命名空间 (例如 'user-service')
port?: number; // 可选,指定服务监听的端口,若不指定或端口被占用则自动选择可用端口
};示例 .env 文件:
IOCORE_MICRO_WEBSOCKET_AGENT_CONFIGS='{"registry":"ws://localhost:8427","namespace":"user-service","port":9001}'使用
通常,Agent 会作为一个独立的 IoCore 应用启动,并定义自己的服务或控制器。
import { Application } from '@iocore/component';
import MicroWebSocketAgent, {
Service,
Controller,
ControllerRequest,
ControllerResponse,
Context,
Next,
Middleware,
} from '@iocore/micro-ws-agent';
// --- 定义 WebSocket Service ---
class MyWsService extends Service {
exec(name: string) {
// 可以通过 this.fetch 调用其他服务
// const result = await this.fetch('other-service/someApi', [arg1]);
return `Hello from WebSocket Service, ${name}!`;
}
}
// --- 定义 HTTP-like Controller 和 Middleware ---
class MyMiddleware extends Middleware {
@Middleware.InComing.Head('x-request-id') // 从 Header 注入
private requestId: string;
async use(ctx: Context, next: Next) {
console.log('Middleware Start, Request ID:', this.requestId);
ctx.state.middlewareData = 'Data from middleware'; // 向下传递数据
await next();
console.log('Middleware End');
}
}
@Controller.Middleware(MyMiddleware) // 应用中间件
class MyController extends Controller {
@Controller.InComing.Path('id') // 从 URL 路径参数注入
private userId: string;
@Controller.InComing.Query('sort') // 从 URL 查询参数注入
private sortBy: string;
@Controller.InComing.Body // 注入请求体
private requestBody: { message: string };
@Controller.InComing.State('middlewareData') // 从 ctx.state 注入 (由上游中间件设置)
private dataFromMiddleware: string;
async response(): Promise<ControllerResponse> {
console.log('Controller Executing...');
console.log('User ID:', this.userId);
console.log('Sort By:', this.sortBy);
console.log('Request Body:', this.requestBody);
console.log('Data from Middleware:', this.dataFromMiddleware);
// 可以调用其他服务
// const wsResult = await this.fetch('my-ws-service/exec', ['controller']);
return {
body: {
success: true,
data: `Processed user ${this.userId}, sorted by ${this.sortBy}. Message: ${this.requestBody?.message}`,
// wsResult,
},
headers: {
'X-Custom-Header': 'Value from controller',
},
// 设置 cookie 等...
};
}
}
// --- 启动 Agent 应用 ---
@Application.Inject(MicroWebSocketAgent)
class AgentApp extends Application {
@Application.Inject(MicroWebSocketAgent)
private agent: MicroWebSocketAgent;
public async main() {
// 绑定 WebSocket Service
this.agent.wsBinding('/my-ws-service', MyWsService);
// 绑定 HTTP-like Controller
this.agent.httpBinding('/users/:id', MyController);
console.log(`Agent '${this.agent.props.namespace}' ready.`);
// 示例:Agent 内部调用自己的服务
try {
const result = await this.agent.fetch('user-service/my-ws-service', ['internal call']);
console.log('Internal WS call result:', result);
const httpResult = await this.agent.fetch('user-service/users/123?sort=desc', [
{
headers: { 'x-request-id': 'abc-123' },
query: { sort: 'desc' }, // 查询参数也可以在这里提供
params: { id: '123' }, // 路径参数也可以在这里提供
cookie: { session: 'xyz' },
body: { message: 'Hello from internal fetch' },
} as ControllerRequest,
]);
console.log('Internal HTTP call result:', httpResult);
} catch (error) {
console.error('Internal fetch failed:', error);
}
}
}
Application.start(AgentApp);MicroWebSocketAgent 类
constructor(): 解析环境变量配置。initialize(): Promise<void>: 启动 WebSocket 服务器,自动选择端口,连接到注册中心并注册命名空间。IoCore 会自动调用。terminate(): void: 关闭服务器,断开与注册中心的连接。IoCore 会自动调用。props: IOCORE_MICRO_WEBSOCKET_AGENT_CONFIGS: 加载的配置。registry: Channel | undefined: 到注册中心的 WebSocket 通道。where(namespace: string): Promise<Channel>: 通过注册中心查找指定命名空间的服务地址,并建立连接(或返回已有的连接)。createFetcher<R = any>(protocol: string, url: string, props: any[] = [], timeout?: number): Promise<R>: 通过命名空间调用其他服务。protocol通常是 'ws' 或 'http'(模拟)。URL 格式如ws://other-service/api/path或http://other-service/users/:id。- 对于
ws协议,props是直接传递给目标Service的exec方法的参数列表。 - 对于
http协议,props应该是一个包含单个ControllerRequest对象的数组,模拟 HTTP 请求的各个部分。
- 对于
fetch<R = any>(url: string, props: any[] = [], timeout?: number): Promise<R>:createFetcher的快捷方式,默认协议为ws。wsBinding<T extends Service>(url: string, clazz: INewAble<T>): void: 将一个 URL 路径绑定到一个Service类。当收到该路径的ws协议请求时,会自动实例化该类并调用其exec方法。httpBinding<T extends Controller>(url: string, clazz: INewAble<T>): Promise<void>: 将一个 URL 路径(支持参数,如/users/:id)绑定到一个Controller类。当收到该路径的http协议请求时,会执行关联的中间件链和 Controller 的response方法,模拟 HTTP 处理流程。
Service (抽象类)
继承自 BaseContext。
abstract exec(...args: any[]): unknown | Promise<unknown>: 实现此方法来处理ws请求。参数 (args) 来自fetch调用。channel: Channel(注入): 当前请求的 WebSocket 通道。agent: MicroWebSocketAgent(注入): Agent 实例。fetch<R = any>(...): 调用其他服务。
Controller (抽象类)
继承自 Router。
abstract response(): ControllerResponse | Promise<ControllerResponse>: 实现此方法来生成模拟的 HTTP 响应。static Middleware(...args: IMiddleware[]): ClassDecorator: 类装饰器,用于关联中间件到 Controller。channel: Channel(注入)agent: MicroWebSocketAgent(注入)fetch<R = any>(...): 调用其他服务。@Controller.InComing...: 属性装饰器,用于从请求上下文注入数据 (见下方Router)。
Middleware (抽象类)
继承自 Router。
abstract use(ctx: Context, next: Next): Promise<unknown>: 实现此方法来定义中间件逻辑。调用next()将控制权传递给下一个中间件或 Controller。static Dependencies(...args: IMiddleware[]): ClassDecorator: 类装饰器,用于声明当前中间件依赖的其他中间件。Agent 会自动处理依赖顺序。channel: Channel(注入)agent: MicroWebSocketAgent(注入)fetch<R = any>(...): 调用其他服务。@Middleware.InComing...: 属性装饰器,用于从请求上下文注入数据 (见下方Router)。
Router (基类,Controller 和 Middleware 继承)
static readonly InComing: 包含一组属性装饰器,用于将Context中的数据注入到Controller或Middleware的属性中。Head(key?: string): 从ctx.headers注入。Query(key?: string): 从ctx.query注入。Path(key?: string): 从ctx.params(URL 路径参数) 注入。Cookie(key?: string): 从ctx.cookie注入。Body(): 注入整个ctx.body。State(key?: string): 从ctx.state(中间件共享数据) 注入。- 所有装饰器都支持可选的回调函数进行数据转换/校验。
Context
类似 Koa 的上下文对象,在 HTTP 模拟处理流程中使用。
headers: Record<string, string | string[]>query: Record<string, string | string[]>params: Record<string, string>cookie: Record<string, string>body: anystate: Record<string, any>: 用于在中间件之间传递数据。
贡献
欢迎提交 Pull Request。对于重大更改,请先开一个 Issue 来讨论您想要更改的内容。
许可证
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago