译者按:根据墨菲定律:“有可能出错的事情,就会出错”。那么,既然代码必然会出错,我们就应该处理好异常。

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

处理异常是编程非常重要的一点。我们的程序依赖于第三方服务、数据库以及我们的用户,一切都不可预料。数据库可能会宕机,第三方服务可能会崩溃,用户可能会使用错误的参数调用我们的接口。

为了处理各种复杂的情况,我们必须处理好代码异常,下面是代码示例:

app.get('/users/:id', (req, res) => {
const userId = req.params.id
if (!userId) {
return res.sendStatus(400).json({
error: 'Missing id'
})
} Users.get(userId, (err, user) => {
if (err) {
return res.sendStatus(500).json(err)
} res.send(users)
})
})

代码中处理了异常,但是存在问题:

  • 在多处代码处理异常
  • 没有使用Express的异常处理模块来统一处理异常

接下来,我们来一步步优化代码异常处理。

Express异常处理中间件

所有Express的路由处理函数都有第三个参数next,它可以用来调用下一个中间件,也可以将错误传递给错误处理中间件:

app.get('/users/:id', (req, res, next) => {
const userId = req.params.id
if (!userId) {
const error = new Error('missing id')
error.httpStatusCode = 400
return next(error)
} Users.get(userId, (err, user) => {
if (err) {
err.httpStatusCode = 500
return next(err)
} res.send(users)
})
})

使用next(err),Express就知道出错了,并把这个错误传递给错误处理模块。为了处理这些错误,需要添加一个中间件,它有4个参数:

app.use((err, req, res, next) => {
// log the error...
res.sendStatus(err.httpStatusCode).json(err)
})

这样,我们就可以使用中间件统一处理错误了。但是,现在的代码有些重复:创建错误,指定HTTP状态码,使用next(err)…

Fundebug是全栈JavaScript错误监控平台,支持各种前端和后端框架,可以帮助您第一时间发现BUG!

boom

boom是一个兼容HTTP的错误对象,他提供了一些标准的HTTP错误,比如400(参数错误)等。

const boom = require('boom')
app.get('/users/:id', (req, res, next) => {
const userId = req.params.id
if (!userId) {
return next(boom.badRequest('missing id'))
} Users.get(userId, (err, user) => {
if (err) {
return next(boom.badImplementation(err))
} res.send(users)
})
})

错误处理中间件需要稍作修改:

app.use((err, req, res, next) => {
if (err.isServer) {
// log the error...
// probably you don't want to log unauthorized access
// or do you?
}
return res.status(err.output.statusCode).json(err.output.payload);
})

Async/Await错误处理

使用Async/Await之后,可以这样处理Express异常:

  • 将中间件使用Promise封装起来,使用catch统一处理异常
  • 在中间件中,直接抛出异常就可以了
const boom = require('boom');
// wrapper for our async route handlers
// probably you want to move it to a new file
const asyncMiddleware = fn => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch((err) => {
if (!err.isBoom) {
return next(boom.badImplementation(err));
}
next(err);
});
};
// the async route handler
app.get('/users/:id', asyncMiddleware(async (req, res) => {
const userId = req.params.id
if (!userId) {
throw boom.badRequest('missing id')
} const user = await Users.get(userId)
res.json(user)
}))

参考

  • 验证HTTP请求参数可以使用joi模块
  • 打印日志可以使用winston或者pino模块
版权声明:
转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/12/06/handle-express-error/

如何处理Express异常?的更多相关文章

  1. nodejs express异常捕获

    参考链接: http://blog.coinidea.com/web开发/nodejs-1131.html 由于nodejs是非阻塞单进程单线程的,一旦nodejs抛出异常,整个服务就会停掉.服务将会 ...

  2. Workflow_如何处理标准异常和自定义异常(案例)

    2014-05-31 Created By BaoXinjian

  3. 如何处理python异常

    1.python异常有那些? window的机器如果安装了python,则直接可以在idle中查看,打开idle,按F1即可打开帮助文档,按如下路径即可查看,也可以去python官网查看这里不说明了百 ...

  4. Java8的flatMap如何处理有异常的函数

    Java8的flatMap函数,作用是:如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional. 见到的映射函数往往都只有一句话,连大括号都不需要加的,如下: ...

  5. [译]MVC网站教程(二):异常管理

    介绍 “MVC网站教程”系列的目的是教你如何使用 ASP.NET MVC 创建一个基本的.可扩展的网站. 1)   MVC网站教程(一):多语言网站框架 2)   MVC网站教程(二):异常管理 3) ...

  6. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  7. [C#] C# 知识回顾 - 学会处理异常

    学会处理异常 你可以使用 try 块来对你觉得可能会出现异常的代码进行分区. 其中,与之关联的 catch 块可用于处理任何异常情况. 一个包含代码的 finally 块,无论 try 块中是否在运行 ...

  8. 浅谈java异常[Exception]

    学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java! 一. 异常的定义 在<java编程思想 ...

  9. 窥探Swift编程之错误处理与异常抛出

    在Swift 2.0版本中,Swift语言对其错误处理进行了新的设计,当然了,重新设计后的结果使得该错误处理系统用起来更爽.今天博客的主题就是系统的搞一下Swift中的错误处理,以及看一下Swift中 ...

随机推荐

  1. Python面向对象6:抽象类和自定义类

    抽象类- 抽象方法: 没有具体实现内容的方法成为抽象方法- 抽象方法的主要意义是规范了子类的行为和接口- 抽象类的使用需要借助abc模块 import abc - 抽象类:包含抽象方法的类叫抽象类,通 ...

  2. Python学习笔记【第十二篇】:Python异常处理

    什么是异常 异常就是程序运行时发生错误的信号,在python中,错误触发的异常如下 错误类型分为两种:语法错误和业务逻辑错. 异常的类型 AttributeError 试图访问一个对象没有的树形,比如 ...

  3. HC-06蓝牙模块的使用

    HC-06蓝牙模块与HC-05的AT指令变化还是挺大的,在模块上电后红灯闪烁表示未连接成功,常亮表示连接成功,期间只要红灯处于闪烁即是进入了AT模式,可发送AT指令,灯常亮使用AT指令无效.下面是常用 ...

  4. Asp.net 性能监控之压测接口“卡住” 分析

    问题描述:web api项目接口压测.前期并发100,500没出现问题,平均耗时也在几百毫秒.当并发1000时候,停留等待许久,看现象是jemeter卡住,没返回,时间过了许久,才正常. 解决过程: ...

  5. 2.Git基础-仓库的获取方式与Git文件的状态变化周期(生命周期)

    1.仓库的获取 Git仓库的获取有两种方式: 1.从现有目录或者是项目中导入所有文件到Git中. 2.从一个服务器clone一个现有的Git仓库. 如果使用第一种方式,只需要在你希望被Git进行管理的 ...

  6. mysql 开发基础系列4 字符数据类型

    字符串类型 1.1 CHAR 和VARCHAR 类型 CHAR 列的长度固定为创建表时声明的长度,VARCHAR 列中的值为可变长字符串.在检索的时候,CHAR 列删除了尾部的空格,而VARCHAR ...

  7. Workspace in use or cannot be created, choose a different one.错误的解决办法

    eclipse 或 myeclipse 使用一段时间后,有时会因为一些故障自己就莫名奇妙的关闭了,再打开时有时没有问题,有时有会提示错误: Workspace Unavailable: Workspa ...

  8. DWR第五篇之文件上传

    1. 在第一篇架构基础上进行 2. 修改maven依赖 <dependencies> <dependency> <groupId>org.directwebremo ...

  9. mysql的"双1设置"-数据安全的关键参数(案例分享)

    mysql的"双1验证"指的是innodb_flush_log_at_trx_commit和sync_binlog两个参数设置,这两个是是控制MySQL 磁盘写入策略以及数据安全性 ...

  10. Gradle nexus 解决开发机器不连网无法下载gradle插件问题

    在用gradle时常规配置如下(D:\gradle-4.9\init.d\init.gradle文件,没有这个文件时自建): ext { nexus = 'http://192.168.127.128 ...