1.0.11 • Published 9 months ago

@iocore/http v1.0.11

Weekly downloads
-
License
-
Repository
-
Last release
9 months ago

@iocore/http

npm version

IoCore 的 HTTP 服务器模块。

基于 Koa 和 find-my-way,提供了一个健壮且高效的 HTTP 服务器框架,集成了 IoCore 的组件化和依赖注入特性,支持 Controller、Middleware 和路由参数注入。

安装

npm install @iocore/http @iocore/component koa koa-compose find-my-way --save
# or
yarn add @iocore/http @iocore/component koa koa-compose find-my-way

依赖

  • @iocore/component: IoCore 核心组件系统。
  • koa: 下一代 Node.js web 框架。
  • koa-compose: 组合 Koa 中间件。
  • find-my-way: 高性能的 HTTP 路由器。

配置

通过环境变量 IOCORE_HTTP_CONFIGS 配置 HTTP 服务器。该变量应包含一个 JSON 字符串。

import { Config, HTTPVersion } from 'find-my-way';

export type IOCORE_HTTP_CONFIGS = {
  port: number; // 服务器监听的端口
  keys?: string[]; // Koa 的签名密钥 (用于 cookie 签名等),默认自动生成
  defaultSuffix?: string; // 绑定 Controller 时,如果 url 以此后缀结尾,则自动移除 (默认 '/index')
} & Omit<Config<HTTPVersion.V1>, 'defaultRoute'>; // find-my-way 的配置选项 (除了 defaultRoute)

示例 .env 文件:

IOCORE_HTTP_CONFIGS='{"port":3000,"ignoreTrailingSlash":true,"caseSensitive":false}'

find-my-way 的配置选项包括 ignoreTrailingSlash, ignoreDuplicateSlashes, maxParamLength, allowUnsafeRegex, caseSensitive 等。详情请参阅 find-my-way 文档

使用

定义 Controller 和 Middleware

Controller 和 Middleware 都是 IoCore 组件,继承自相应的基类。

import { Application } from '@iocore/component';
import Http, {
  Controller,
  Middleware,
  Next,
  Context,
} from '@iocore/http';

// --- 中间件定义 ---
class LoggerMiddleware extends Middleware {
  // 从 Koa Context 注入数据
  @Middleware.InComing.Head('user-agent')
  private userAgent: string;

  async use(ctx: Context, next: Next) {
    const start = Date.now();
    console.log(`--> ${ctx.method} ${ctx.path} (User-Agent: ${this.userAgent})`);
    await next();
    const ms = Date.now() - start;
    console.log(`<-- ${ctx.method} ${ctx.path} - ${ctx.status} (${ms}ms)`);
  }
}

@Middleware.Dependencies(LoggerMiddleware) // 声明依赖,确保 LoggerMiddleware 先执行
class AuthMiddleware extends Middleware {
  @Middleware.InComing.Query('token')
  private token: string;

  async use(ctx: Context, next: Next) {
    if (this.token === 'valid-token') {
      ctx.state.user = { id: '123', name: 'Admin' };
      await next();
    } else {
      ctx.status = 401;
      ctx.body = 'Unauthorized';
    }
  }
}

// --- Controller 定义 ---
@Controller.Method('GET') // 响应 GET 请求
@Controller.Middleware(AuthMiddleware) // 应用 AuthMiddleware (LoggerMiddleware 会自动因依赖关系先执行)
class UserController extends Controller {
  // 从 URL 路径参数注入
  @Controller.InComing.Path('userId')
  private userId: string;

  // 从上游中间件设置的 ctx.state 注入
  // @Controller.InComing.State('user') // State 注入当前版本似乎在 router.ts 未实现
  // private currentUser: { id: string, name: string };

  async response(next: Next): Promise<any> {
    const currentUser = this.ctx.state.user; // 手动从 ctx.state 获取
    return {
      message: `Hello User ${this.userId}! Welcome, ${currentUser.name}!`,
    };
  }
}

@Controller.Method('POST') // 响应 POST 请求
class DataController extends Controller {
  // 注入解析后的请求体 (需要配合 koa-body 等中间件使用)
  @Controller.InComing.Body
  private data: any;

  response(next: Next) {
    console.log('Received data:', this.data);
    return { received: true, data: this.data };
  }
}

// 标记为弃用,将不会被绑定
@Controller.Method('GET')
@Controller.Deprecated
class OldController extends Controller {
  response(next: Next) {
    return 'This is deprecated';
  }
}

// --- 启动应用 ---
@Application.Inject(Http)
class MyApp extends Application {
  @Application.Inject(Http)
  private http: Http;

  public async main() {
    // --- 添加全局 Koa 中间件 (例如 body-parser) ---
    // 需要先安装: npm install koa-body
    try {
      const { koaBody } = await import('koa-body');
      // 在路由处理前添加 (prefix hook)
      this.http.hooks.add('prefix', koaBody());
      console.log('koa-body middleware added.');
    } catch (e) {
      console.warn('koa-body not installed, POST body parsing might not work.');
    }

    // --- 绑定 Controller ---
    // 将 /users/:userId 路径绑定到 UserController
    const unbindUser = await this.http.bind('/users/:userId', UserController);

    // 将 /data 路径绑定到 DataController
    const unbindData = await this.http.bind('/data', DataController);

    // OldController 不会被绑定,因为标记了 @Controller.Deprecated
    await this.http.bind('/old', OldController);

    console.log(`HTTP server listening on port ${this.http.props.port}`);

    // 可以选择性地解绑路由
    // if (unbindUser) unbindUser();
  }
}

Application.start(MyApp);

Http

核心 HTTP 服务器组件。

  • constructor(): 解析环境变量配置。
  • initialize(): Promise<void>: 初始化 Koa 应用、find-my-way 路由器和 HTTP 服务器,并开始监听指定端口。IoCore 会自动调用。
  • terminate(): void: 关闭 HTTP 服务器。IoCore 会自动调用。
  • koa: Koa: Koa 应用实例。
  • app: Instance (find-my-way 实例): 路由器实例,可以用于更底层的路由操作。
  • server: Server: Node.js HTTP 服务器实例。
  • props: IOCORE_HTTP_CONFIGS: 加载的配置。
  • hooks: HttpMiddlewareHooks: 用于添加全局前置/后置 Koa 中间件的 Hook 点。
  • bind<T extends INewAble<Controller>>(url: string, controller: T): Promise<void | (() => void)>: 将一个 URL 路径绑定到一个 Controller 类。它会自动处理 @Controller.Method@Controller.Middleware@Controller.Deprecated 装饰器,并将解析后的中间件和 Controller 处理逻辑注册到路由器。返回一个可选的解绑函数。
    • URL 路径支持 find-my-way 的参数语法 (例如 /users/:id)。
    • 如果 URL 以配置的 defaultSuffix (默认为 '/index') 结尾,该后缀会被自动移除。
    • URL 中的 [param] 会被自动替换为 :param

Controller (抽象类)

继承自 Router

  • abstract response(next: Next): T | Promise<T>: 实现此方法来处理请求并返回响应体。如果方法返回 undefined,则不会修改 ctx.body
  • static Method(...args: HTTPMethod[]): ClassDecorator: 类装饰器,指定 Controller 处理的 HTTP 方法 (例如 'GET', 'POST')。
  • static Middleware(...args: IMiddleware[]): ClassDecorator: 类装饰器,将 Koa 中间件或自定义 Middleware 类关联到 Controller。
  • static Deprecated: ClassDecorator: 类装饰器,标记 Controller 为弃用,http.bind 将忽略它。
  • ctx: Context (注入): 当前请求的 Koa 上下文。
  • @Controller.InComing...: 属性装饰器,用于从 Koa Context 注入数据。

Middleware (抽象类)

继承自 Router。用于创建可复用的、支持依赖注入的自定义中间件。

  • abstract use(ctx: Context, next: Next): Promise<unknown>: 实现此方法来定义中间件逻辑。调用 await next() 将控制权传递给下一个中间件。
  • static Dependencies(...args: IMiddleware[]): ClassDecorator: 类装饰器,声明当前中间件依赖的其他中间件(可以是 Koa 中间件或自定义 Middleware 类)。绑定 Controller 时会自动处理依赖顺序。
  • ctx: Context (注入): 当前请求的 Koa 上下文。
  • @Middleware.InComing...: 属性装饰器,用于从 Koa Context 注入数据。

Router (基类,ControllerMiddleware 继承)

  • static readonly InComing: 包含一组属性装饰器,用于将 Koa Context 中的数据注入到 ControllerMiddleware 的属性中。
    • Head(key?: string): 从 ctx.headersctx.request.headers 注入。
    • Query(key?: string): 从 ctx.queryctx.request.query 注入。
    • Path(key?: string): 从 ctx.params (URL 路径参数) 注入。
    • Body(): 注入 ctx.request.body (需要配合 body 解析中间件)。
    • 所有装饰器都支持可选的回调函数进行数据转换/校验。

HttpMiddlewareHooks

一个单例组件,用于管理全局 Koa 中间件。

  • add(type: 'prefix' | 'suffix', ...middlewares: Middleware[]): this: 添加全局中间件。
    • prefix: 在 find-my-way 路由处理 之前 执行。
    • suffix: 在 find-my-way 路由处理 之后 执行 (如果路由未匹配或路由处理器调用了 next())。
  • del(type: 'prefix' | 'suffix', ...middlewares: Middleware[]): this: 移除全局中间件。
  • compose(type: 'prefix' | 'suffix'): Middleware: (内部使用) 获取组合后的中间件函数。

贡献

欢迎提交 Pull Request。对于重大更改,请先开一个 Issue 来讨论您想要更改的内容。

许可证

MIT

1.0.11

9 months ago

1.0.10

9 months ago

1.0.9

9 months ago

1.0.8

10 months ago

1.0.7

10 months ago

1.0.6

10 months ago

1.0.5

10 months ago

1.0.4

10 months ago

1.0.3

10 months ago

1.0.2

10 months ago

1.0.1

10 months ago

1.0.0

10 months ago