npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zenweb/controller

v6.6.1

Published

Zenweb Controller module

Readme

zenweb 控制器与路由发现

zenweb 模块 - 控制器与路由发现

演示

简单使用

在 src/controller 目录下新建一个文件 simple.ts

import { Context, Middleware, Next } from '@zenweb/core';
import { Injectable, Init } from '@zenweb/inject';
import { All, Controller, Get, Mapping, Post } from '@zenweb/controller';

async function demoMiddleware(ctx: Context, next: Next) {
  console.log('demo middleware before');
  await next();
  console.log('demo middleware after');
}

function funcMiddleware(name: string): Middleware {
  return async function (ctx, next) {
    console.log(`middleware [${name}] before`);
    await next();
    console.log(`middleware [${name}] after`);
  }
}

// 控制器全局中间件
// 控制器注解并不是必须的,只有需要进行特定配置时使用
@Controller({
  middleware: demoMiddleware,
})
export class Simple {
  // 构造器函数中的参数都是自动注入
  constructor(
    private ctx: Context,
  ) {}

  @Init // 控制器每次被请求时候都会执行
  init(ctx: Context) { // ctx 变量会自动注入
    console.log('init:', ctx.path);
  }

  @Get()
  index(ctx: Context) { // 在方法中的变量都是自动注入的
    console.log('index:', ctx.ip);
    return 'index:' + this.ctx.ip;
  }

  // 映射一个路径, 不指定参数默认为 `GET /方法名`
  @Get()
  @Get('/s2', funcMiddleware('s2')) // 给路由添加中间件
  simple() {
    console.log('simple')
    return 'simple';
  }

  // 一次性定义多个方法*路径*中间件
  @Mapping({
    method: ['POST', 'GET'],
    path: ['/aaa', '/bbb'],
    middleware: funcMiddleware('aaa'),
  })
  aaa() {
    return 'aaa';
  }

  @Post(funcMiddleware('post')) // 第一个参数可以是路径,也可以是中间件
  post() {
    return 'POST method';
  }

  @All(funcMiddleware('all-1'), funcMiddleware('all-2')) // 使用多个中间件
  all() {
    return 'any method';
  }
}
@Injectable('request') // request 级别的中间件为默认值,可以不用指定,与直接使用 @Injectable 相同
export class RequestController {
  @Get()
  req() {
    return 'req';
  }
}

@Controller({ prefix: '/singleton' })
@Injectable('singleton') // 标记为单例类型,class 只会被初始化一次,且不销毁
export class SingletonController {
  i = 0; // 单例变量不会被销毁

  @Get()
  index() {
    return this.i++; // 每次请求都会 +1
  }
}

:::tip 注意 控制器方法中 return 数据如果需要统一处理需要安装 @zenweb/result 模块,否则 return 数据会被设置到 ctx.body 上 :::

使用中间件

import { Context, Next, Get, Controller } from 'zenweb';

// 定义一个中间件处理函数
function actionLog(ctx: Context, next: Next) {
  console.log('actionLog middleware')
  return next();
}

export class Controller {
  // 方法上的中间件
  @Get(actionLog)
  simple() {
    return 'simple';
  }
}

// 控制器中间件,作用与所有控制器方法上
@Controller({
  middleware: actionLog,
})
export class Controller2 {
  @Get()
  simple() {
    return 'simple';
  }
}

自动路径映射规则

如果开启 autoControllerPrefix 功能,则会自动为控制器方法添加路径前缀,等同于自动给控制器类添加 @Controller({ prefix }) 选项

文件名规则

控制器扫描目录为 src/controller 下的文件结构

| 文件名 | 映射路径 | 说明 | | --- | --- | --- | | index.ts | / | index 名称为特殊名称,代表首页,所以默认为根路径 / | | user.ts | /user | 非 index 文件名都会被映射为路径名 | | user/index.ts | /user | 同理即使是子目录下面的 index 文件名会当成子目录的根路径处理 | | user/profile.ts | /user/profile | 子目录下面的文件名会当成子目录的子路径处理 |

prefix 的处理规则

映射路径会自动修改控制器的 prefix 配置项,但是有如下几种特殊的处理规则:

  1. prefix 值没有设置时直接使用自动路径值
  2. 已经设置的 prefix 值如果开头为 /(例如: prefix: '/admin')则不做任何处理(忽略)
  3. 已经设置的 prefix 值没有使用 / 开头(例如: prefix: 'admin'),则会在原来已经设置的结果前添加自动路径值。例如自动路径为 /manage/some 控制器值 prefix: 'admin' 则会变为 prefix: '/manage/some/admin'

控制器内方法映射规则

即使没有开启 autoControllerPrefix 功能也不会影响控制器内方法的映射规则

class SomeController {
  @Get() // 默认映射路径为 /
  index() {}

  @Get() // 默认映射路径为 /detail
  detail() {}

  @Get() // 默认映射路径为 /detail_by_id
  detail_by_id() {}

  @Get() // 默认映射路径为 /detail/:id
  'detail/:id'(ctx: Context) { return ctx.params.id }
}

使用技巧

统一管理后台接口

例如后台管理接口中需要统一添加 /admin 作为前缀,并且需要验证管理员身份,则可以这样使用

import { Mapping, Middleware, RouterMethod, RouterPath } from 'zenweb';

/**
 * 管理员验证中间件
 */
export function adminRequired(): Middleware {
  return function (ctx, next) {
    if (!ctx.admin) {
      fail('没有权限');
    }
    return next();
  }
}
s
/**
 * 管理后台路径统一映射
 */
export function AdminMapping(method?: RouterMethod, path?: RouterPath, ...middleware: Middleware[]) {
  return Mapping({
    method,
    prefix: '/admin',
    path,
    middleware: [adminRequired(), ...middleware],
  });
}
import { Context, Next, Mapping, Controller } from 'zenweb';
import { AdminMapping } from './_helper';

export class IndexController {
  // 等同于 @Mapping({ path: '/admin/', method: 'GET', middleware: [adminRequired()] })
  @AdminMapping()
  index() {
    return 'admin index';
  }

  // 等同于 @Mapping({ path: '/admin/create_user', method: 'POST', middleware: [adminRequired()] })
  @AdminMapping('POST')
  create_user() {
    return 'create user';
  }
}