koa2 错误处理及404

404 处理

现在我们访问一个不存在的路由http://localhost:3000/404 默认会返回

  1. Not Found

通常我们需要自定义 404 页面,新建一个views/404.html

  1. {% extends 'views/base.html' %}
  2. {% block body %}
  3. <div class="page-404 has-background-light has-text-centered">
  4. <pre>
  5. .----.
  6. _.'__ `.
  7. .--($)($$)---/#\
  8. .' @ /###\
  9. : , #####
  10. `-..__.-' _.-\###/
  11. `;_: `"'
  12. .'"""""`.
  13. /, ya ,\\
  14. // 404! \\
  15. `-._______.-'
  16. ___`. | .'___
  17. (______|______)
  18. </pre>
  19. <p class="subtitle is-3">迷路了…</p>
  20. <a href="javascript:history.back();" class="button is-primary">上一页</a>
  21. <a href="/" class="button is-link">回主页</a>
  22. </div>
  23. {% endblock %}

修改 routes/index.js,在路由最后加上

  1. // 404
  2. app.use(async (ctx, next) => {
  3. await ctx.render('404', {
  4. title: 'page not find'
  5. })
  6. })

现在随便访问一个未定义的路由如:http://localhost:3000/404 将出现如下页面

404

错误处理

try catch

在koa2中,出现错误,会直接将错误栈打印到控制台。因为使用了async、await,可以方便的使用 try-catch 来处理错误,同时我们可以让最外层的中间件,负责所有中间件的错误处理。创建你自己的错误处理程序:

  1. app.use(async (ctx, next) => {
  2. try {
  3. await next()
  4. } catch (err) {
  5. ctx.status = err.statusCode || err.status || 500;
  6. ctx.body = {
  7. message: err.message
  8. };
  9. }
  10. })

注意:这个错误处理中间件应该放在最外层即中间件链的起始处。

我们也可以为它指定自定义错误页,新建一个你自己喜欢的error.html

修改 middlewares/error_handler.js

  1. module.exports = function errorHandler () {
  2. return async (ctx, next) => {
  3. try {
  4. await next()
  5. } catch (err) {
  6. ctx.status = err.statusCode || err.status || 500
  7. await ctx.render('error', {
  8. title: ctx.status
  9. })
  10. }
  11. }
  12. }

在index.js 引入并使用

  1. const error = require('./middlewares/error_handler')
  2. ...
  3. app.use(error())
  4. ...

现在在程序中随便抛出个错误试试

error 事件

运行过程中一旦出错,Koa 会触发一个error事件。监听这个事件,也可以处理错误

  1. app.on('error', (err, ctx) =>
  2. console.error('server error', err)
  3. )

需要注意的是,如果错误被try...catch捕获,就不会触发error事件。这时,必须调用ctx.app.emit(),手动释放error事件,才能让监听函数生效。修改下之前的错误处理中间件,在渲染自定义错误页后添加如下代码手动释放error 事件。这下控制台也能打印出错误详情

  1. ctx.app.emit('error', err, ctx)