前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >​如何处理Express和Node.js应用程序中的错误

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

作者头像
前端知否
发布2020-03-23 18:03:05
5.6K0
发布2020-03-23 18:03:05
举报
文章被收录于专栏:前端知否

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

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

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

代码语言:javascript
复制
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路由,以便我们可以轻松地在浏览器中测试路由。

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

代码语言:javascript
复制
app.HTTPMethod(path, middleware)
// HTTPMethod = get, post, put, delete …
代码语言:javascript
复制

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

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

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

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

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

代码语言:javascript
复制
Welcome to the main route!
代码语言:javascript
复制

访问localhost:3000/about:

代码语言:javascript
复制
This is the about route!
代码语言:javascript
复制
Express如何查找路由?

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

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

代码语言:javascript
复制
Cannot GET /contact
代码语言:javascript
复制

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

如何利用路由顺序

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

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

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

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

app.listen(port …

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

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

代码语言:javascript
复制
{ "status": 404, "error": "Not found" }

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

处理任何类型的错误

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

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

代码语言:javascript
复制
…
app.get(‘/’, (req, res, next) => {
throw new Error(‘Something went wrong!’);
 res.send(‘Welcome to main route!’)
})
…
代码语言:javascript
复制

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

定义错误处理中间件

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

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

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

代码语言:javascript
复制
Something Broke!

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

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

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

更新index.js:

代码语言:javascript
复制
…
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’,
    },
  });
});
…
代码语言:javascript
复制

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

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

代码语言:javascript
复制
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}`));
代码语言:javascript
复制

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

代码语言:javascript
复制
app.use((error, req, res, next) => {
console.error(error); // 打印输出错误
 res.render('errorPage') // 渲染错误页面给用户
});
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端知否 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 错误来源
  • 通过路由排序处理路由错误
  • Express如何查找路由?
  • 如何利用路由顺序
  • 处理任何类型的错误
  • 定义错误处理中间件
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档