【问题标题】:Koa@2 error handlingKoa@2 错误处理
【发布时间】:2018-08-20 01:37:54
【问题描述】:

我正在使用 Koa 构建一个 API。我的所有路线都使用 koa-router。每个路由都使用一个控制器,该控制器具有给定 mongoose 模型的所有逻辑。我已阅读Koa docs on error-handling 并了解awaiting 在try/catch 块中的使用。他们提到应该在中间件链的开头设置一个默认错误处理程序。因此,如果我有类似以下的内容,我应该对router.get() 的路线进行合理的错误处理:

const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();
const router = new Router();

app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    err.status = err.statusCode || err.status || 500;
    throw err;
  }
});

router
    .get('/', async (ctx, next) => {
    console.log('Got Route');
    //ctx.body = users;
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000, () => console.log('Koa app listening on 3000'));

如果我要在这条路线上稍微复杂一些,在路线内添加另一个try/catch 有什么好处吗?

router
    .put('/', async function updateOnServer(ctx, next) {
        try {
            await Model.updateOne({
                _id: ctx.params.id,
            }, {
                field1: ctx.request.body.field1,
                $push: { field2: ctx.request.body.field2 },
            }).exec();
        } catch (e) {
            console.log(e);
        }

        await next();
});

我只是在这里添加冗余错误处理吗?

【问题讨论】:

    标签: javascript error-handling koa


    【解决方案1】:

    我在上面的评论中错了 - Koa 的默认错误处理程序并不总是抛出内部服务器错误。这取决于您抛出的错误类型。但是,我更喜欢简单地抛出字符串,并使用 JavaScript 自己的 throw 语句。所以,我实现了一个简单的 Koa 错误处理程序,它允许我这样做:

    throw `404: User ${id} not found`;
    

    这会导致发回状态 404,其中包含“未找到用户 5”之类的消息。这是我的 Koa 中间件(如果你抛出字符串以外的东西,或者字符串的格式不正确,它会退回到 Koa 的内置错误处理程序):

    app.use(async (ctx, next) => {
        try {
            await next();
            }
        catch (err) {
            if (typeof err === 'string') {
                let lMatches = err.match(/^(\d{3}):\s*(.*)$/);
                if (lMatches) {
                    ctx.status = Number(lMatches[1]);
                    ctx.body = lMatches[2];
                    }
                else throw err;  // use default error handler
                }
            else throw err;  // use default error handler
            }
        });
    

    【讨论】:

      【解决方案2】:

      我重新阅读了有关错误处理的文档,并在 Koa Wiki 上找到了这个小技巧。由此,我得出以下结论:

      Koa Error Handling states

      但是,默认错误处理程序对于大多数用例来说已经足够了。

      这种情况下的默认错误处理程序是 Koa-built-in 错误处理程序。您不需要在编写的代码中包含任何类型的自定义错误处理。 Koa 会写出堆栈跟踪以及错误消息等。

      如果您想修改错误的处理方式,请在中间件链的最开始添加类似建议的中间件:

      app.use(async (ctx, next) => {
        try {
          await next();
        } catch (err) {
          err.status = err.statusCode || err.status || 500;
          ctx.body = err.message;
          ctx.app.emit('error', err, ctx);
        }
      });
      

      如果您想为特定路线或特殊逻辑再次更改它,然后在该点添加另一个 try/catch 块(根据我的上述):

      router
          .put('/', async function updateOnServer(ctx, next) {
              try {
                  await Model.updateOne({
                      _id: ctx.params.id,
                  }, {
                      field1: ctx.request.body.field1,
                      $push: { field2: ctx.request.body.field2 },
                  }).exec();
              } catch (e) {
                  ctx.status = 418;
                  ctx.body = "a custom error message, with nothing really helpful";
              }
      
              await next();
      });
      

      【讨论】:

      • 我是个矮胖的茶壶
      • 默认的 Koa 错误处理程序似乎总是抛出一个内部服务器错误。我宁愿区分这种形式的未捕获异常和请求中的错误,这当然不是内部服务器错误。我也宁愿使用 throw() 而不是 ctx.throw() 因为我的许多库对 Koa 或上下文对象一无所知,也不应该一无所知。
      • @sansSpoon 你没忘记ctx.status = err.status;这样的东西吗?
      猜你喜欢
      • 2015-06-19
      • 1970-01-01
      • 2016-08-28
      • 1970-01-01
      • 1970-01-01
      • 2016-12-28
      • 1970-01-01
      • 2016-03-14
      • 2017-01-01
      相关资源
      最近更新 更多