在 TypeScript 的 Koa 调试模式下,如何使自定义中间件函数记录到控制台?

How do I make a custom middleware function get logged to console while in Koa debug mode in TypeScript?

使用 Koa v2.7.0 和 TypeScript v3.3.1

我的 "errorHandler" 中间件函数是这样导出的

export const clientErrorHandler = () => {
    return async (ctx: Context, next: NextFunction) => {
        try{
            await next();
        }
        catch (err){
            if(err instanceof HTTPClientError){
                console.warn(err);
                ctx.status = err.statusCode;
                ctx.body = err.message;
                ctx.app.emit('error', err, ctx);
           }
       }
   }
}

我在给定 Koa 应用程序上处理中间件附件的逻辑如下所示:

export const handleErrors = (app: Koa) => {
    const serverErrHandler = serverErrorHandler();
    serverErrHandler._name = 'serverErrorHandler';
    app.use(serverErrHandler)
}

我尝试创建此 属性 的原因是由于此 Koa 文档(请参阅下面的 link),其中指出我们可以为中间件函数提供一个 _name 属性这样当我们 运行 设置了 DEBUG=koa* 的程序时,这个中间件函数将能够有一个显示在控制台中的名称。

Since JavaScript does not allow defining function names at runtime, you can also set a middleware's name as ._name. This is useful when you don't have control of a middleware's name. For example:

const path = require('path'); const serve = require('koa-static');
const publicFiles = serve(path.join(__dirname, 'public'));
publicFiles._name = 'static /public';
app.use(publicFiles);

Source of the above snippet: https://github.com/koajs/koa/blob/master/docs/guide.md#debugging-koa

但是,在尝试此操作时,由于我使用的是 TypeScript,它不喜欢我尝试在此匿名函数上设置 属性。

[ts] Property '_name' does not exist on type '(ctx: Context, next: NextFunction) => Promise'.

我希望确定使自己能够将这个小 _name 属性 添加到这个匿名函数的最佳方法,以便我可以获得可靠的调试日志。

当我写这篇文章时,我最终找到了两个可能的解决方案。

我要使用的方法是不使用匿名函数,因此无需修改我的中间件函数上的 _name 属性。重新阅读 koa 文档后,我认为我查看的关键词是

"for middleware that you don't have control over"

我的中间件函数定义现在看起来像这样:

export const clientErrorHandler = () => {
    let clientErrHandler = async (ctx: Context, next: NextFunction) => {
        try{
          await next();
        }
        catch (err){
            if(err instanceof HTTPClientError){
              console.warn(err);
              ctx.status = err.statusCode;
              ctx.body = err.message;
              ctx.app.emit('error', err, ctx);
            }
        }
      }
    return clientErrHandler;
}

现在,如果假设这是您无法控制第三方中间件函数名称并且您使用的是 TypeScript 的情况,我发现这个堆栈溢出解决方案在这种情况下有帮助:

使用 Whosebug 的建议,可以定义一个接口并使用匿名函数进行类型断言,以产生一个结果,让调用者打字稿代码设置 _name 属性 returned 功能没有抱怨没有这样的 属性 存在。

只是为了演示它的样子:

尽管我在您技术上无法修改的代码上进行演示,但我假设您也可以在调用方进行类型断言,然后修改 _name 属性之后。

interface MiddlewareFunction { (ctx: Context, next: NextFunction ): Promise<void>; _name: string; }

export const serverErrorHandler = () => {
  return <MiddlewareFunction> async function (ctx: Context, next: NextFunction){
    try {
      await next();
    }
    catch (err) {
      if(process.env.NODE_ENV === 'production'){
        ctx.status = 500;
        ctx.body = 'Internal Server Error';
      }
      else {
        ctx.status = err.status;
        ctx.body = err.stack;
        ctx.app.emit('error', err, ctx);
      }
    }
  }
}

与问题中的代码相同:

export const handleErrors = (app: Koa) => {
    const serverErrHandler = serverErrorHandler();
    serverErrHandler._name = 'serverErrorHandler';
    app.use(serverErrHandler)
}

编辑:您也可以在 return.

中将箭头函数改回正常的 javascript 函数
export const serverErrorHandler = () => {
  return async function serverErrorHandler (ctx: Context, next: NextFunction){
    try {
      await next();
    }
    catch (err) {
      if(process.env.NODE_ENV === 'production'){
        ctx.status = 500;
        ctx.body = 'Internal Server Error';
      }
      else {
        ctx.status = err.status;
        ctx.body = err.stack;
        ctx.app.emit('error', err, ctx);
      }
    }
  }
}