专栏首页前端知否​如何处理Express和Node.js应用程序中的错误

​如何处理Express和Node.js应用程序中的错误

使用Express创建API时,我们定义了路由及其处理程序。在理想情况下,API的使用者只会向我们定义的路由发出请求,并且路由将正常运行。但是,我们不会生活在理想的世界中:)。Express知道这一点,并使我们API中的错误处理变得轻而易举。

在这篇文章中,我将解释如何处理Express中的错误。

该代码只有一个JavaScript文件index.js,其内容如下:

const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res, next) => {
 res.send("Welcome to main route!");
});

app.get("/about", (req, res, next) => {
 res.send("This is the about route!");
});

app.listen(port, () => console.log(`App listening on port: ${port}`));

创建一个新文件夹,npm init -y,然后创建npm i --save express。在此文件夹中创建index.js并将代码粘贴到其中。

错误来源

Express应用程序中可能会发生两种基本错误。

一种错误是对没有定义路由处理程序的路径发出请求。例如,index.js定义了两条get路由(/ 和 /about)。我正在使用get路由,以便我们可以轻松地在浏览器中测试路由。

请注意,路由定义了请求路径,并对该路径发出请求时调用了中间件函数:

app.HTTPMethod(path, middleware)
// HTTPMethod = get, post, put, delete …

错误的另一个来源是当路由处理程序或代码中的其他任何地方出现问题时。例如,如下更新`ndex.js`中的第一个路由:

…
app.get(‘/’, (req, res, next) => {
// 通过抛出错误来破坏应用程序,从而模仿错误!
throw new Error(‘Something went wrong’);
 res.send(‘Welcome to main route!’)
})
…

重新启动服务器并访问localhost:3000,您将看到一个错误和一个堆栈跟踪信息。

通过路由排序处理路由错误

删除在index.js中引发错误的语句。启动服务器并在浏览器中访问localhost:3000,您应该看到以下消息:

Welcome to the main route!

访问localhost:3000/about:

This is the about route!

Express如何查找路由?

Express创建了一个可以称为路由表的地方,它将路由按照代码中定义的顺序放置。当请求进入Web服务器时,URI通过路由表运行,并且使用表中的第一个匹配项-即使存在多个匹配项。

如果找不到匹配项,则Express将显示错误。要查看实际效果,请访问localhost:3000/contact,浏览器将显示:

Cannot GET /contact

检查路由表后,Express发现/ contact不匹配,因此它以错误响应。

如何利用路由顺序

由于Express在路由表中找不到给定URI时显示错误消息,因此这意味着我们通过确保此路由是路由表中的最后一条来定义用于处理错误的路由。错误路由应匹配哪条路径?

由于我们不知道用户将请求的路径不存在,因此我们无法将路径硬编码到此错误路由中。我们也不知道请求可能使用哪种HTTP方法,因此我们将使用app.use()而不是app.get。

将以下路由放在app.listen()之前的路由声明的末尾,更新index.js:

…
// 这个匹配所有路由和所有请求方法
app.use((req, res, next) => {
 res.status(404).send({
status: 404,
error: ‘Not found’
 })
})

app.listen(port …

重新启动服务器并访问未定义的路径,例如localhost:3000/blog

现在,我们有了一个自定义的错误响应:

{ "status": 404, "error": "Not found" }

请记住,路由的顺序对于此工作非常重要。如果此错误处理路由位于路由声明的顶部,则每个路径(有效和无效)都将与其匹配。我们不希望这样,因此错误处理路由必须最后定义。

处理任何类型的错误

如果我们只想处理从请求到不存在路径的错误,则上一节中的解决方案有效。但是它不能处理我们的应用程序中可能发生的其他错误,并且是处理错误的不完整方法。它只能解决一半的问题。

更新index.js,在第一个get路由中引发错误:

…
app.get(‘/’, (req, res, next) => {
throw new Error(‘Something went wrong!’);
 res.send(‘Welcome to main route!’)
})
…

如果您访问localhost:3000,您仍然会看到Express默认错误处理程序的响应。

定义错误处理中间件

错误处理中间件函数的声明方式与其他中间件函数相同,只是它们具有四个参数而不是三个参数。例如:

// 错误处理中间件
app.use((error, req, res, next) => {
console.error(error.stack);
 res.status(500).send(‘Something Broke!’);
})

将此代码放在app.listen之前和第一个app.use之后,然后重新启动服务器,然后访问localhost:3000。现在的响应是:

Something Broke!

现在,我们正在处理两种类型的错误。啊哈!

这行得通,但是我们可以改善它吗?是的。

当您将参数传递给next()时,Express会假定这是一个错误,它将跳过所有其他路由,并将传递给next()的所有内容发送到已定义的错误处理中间件。

更新index.js:

…
app.use((req, res, next) => {
const error = new Error(“Not found”);
 error.status = 404;
 next(error);
});

// 错误处理中间件
app.use((error, req, res, next) => {
  res.status(error.status || 500).send({
error: {
status: error.status || 500,
message: error.message || ‘Internal Server Error’,
    },
  });
});
…

现在,处理错误请求的中间件功能将移交给错误处理程序中间件。next(error)表示:“嘿,错误处理程序先生,我有一个错误,请处理!”。

为了确保您与我在同一页面上,请输入error.status ||。500表示如果错误对象没有status属性,我们将500用作状态代码。index.js的完整内容是:

const express = require("express");

const app = express();
const port = 3000;

app.get("/", (req, res, next) => {
throw new Error("Something went wrong!");
  res.send("Welcome to main route!");
});

app.get("/about", (req, res, next) => {
  res.send("This is the about route!");
});

app.use((req, res, next) => {
const error = new Error("Not found");
  error.status = 404;
  next(error);
});

// 错误处理中间件
app.use((error, req, res, next) => {
  res.status(error.status || 500).send({
    error: {
      status: error.status || 500,
      message: error.message || 'Internal Server Error',
    },
  });
});

app.listen(port, () => console.log(`App listening on port: ${port}`));

如果您提供的是静态页面而不是发送JSON响应,则逻辑仍然相同。您只需要更改错误处理程序中发生的事情即可。例如:

app.use((error, req, res, next) => {
console.error(error); // 打印输出错误
 res.render('errorPage') // 渲染错误页面给用户
});

本文分享自微信公众号 - 前端知否(qianduanzhifou),作者:QETHAN

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-02-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Flutter必备语言Dart教程02 - 控制流,异常

    我们已经完成了Dart中的变量,类型和函数的学习(如果你还没有读过它,请阅读Flutter必备语言Dart教程01 - 变量,类型,函数),现在我们来看看Dar...

    前端知否
  • 使用React Hooks进行状态管理 - 无Redux和Context API

    现在,我们将探索和开发一个自定义Hook来管理全局状态 - 比Redux更容易使用的方法,并且比Context API更高效。

    前端知否
  • Vue.js中的延迟加载和代码拆分

    虽然现在网络环境和电子设备变得越来越好,但是保持应用程序快速加载变得越来越困难。在本系列中,我将深入研究我们在实践中使用的Vue性能优化技术,并且您可以在Vue...

    前端知否
  • 幽灵404 页面源码 跟随鼠标动画

    在线演示: https://www.zmki.cn/danye/404youling/

    AlexTao
  • python开发_thread_布朗运动

    ===================================================

    Hongten
  • 什么是交叉熵啊?| 小白深度学习入门

    热力学那个先不说,这里准确的说是“信息熵”。而要知道什么是信息熵,我们得知道什么是信息。

    叶锦鲤
  • SD-WAN全球部署的三大挑战:ISP、Peering和中国防火墙的管理

    SD-WAN市场正在蓬勃发展,分析人士估计,未来几年,该空间创造的服务和设备收入将达到数十亿美元。然而,在全球企业中管理这种部署仍然面临着财政和业务的挑战。

    SDNLAB
  • 程序员为什么会有职业瓶颈?

    2019年初,俗话说"金三银四"。这时候面试不知道你们慌不慌张。因为2018年冬天是寒冷的。其实18年的低温持续时间不算很长,我也没有披上军大衣。但是突如其来的...

    Java团长
  • 技术规范(2): 后端技术开发规范

    PEP8 规范: https://www.python.org/dev/peps/pep-0008/

    机械视角
  • ubuntu 16.04 搭建pptpd V**服务器

    注意:经实测,配置完iptables NAT转发之后手机可以上网,但是电脑不能。配置完MTU之后,电脑手机都可以上网。

    羽翰尘

扫码关注云+社区

领取腾讯云代金券