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

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

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

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

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. git学习笔记 看廖大神视频小记

    1.创建一个空目录 $ mkdir gittemp $cd gittemp $pwd //x显示当前目录 2.$ git init 把这个目录变成git可以管理的仓库 多的一个隐藏的.git 目录 可 ...

  2. Eclipse环境搭建并且运行wordcount程序

    一.安装Hadoop插件 1. 所需环境  hadoop2.0伪分布式环境平台正常运行 所需压缩包:eclipse-jee-luna-SR2-linux-gtk-x86_64.tar.gz 在Linu ...

  3. Javascript高级编程学习笔记(39)—— DOM(5)Comment

    Comment类型 顾名思义,comment类型指的就是注释节点在HTML文档中的类型 也就是说平时我们在代码中的注释,在HTML解析的时候也会被解析为一类节点 让我们可以根据这些节点进行一系列的操作 ...

  4. 吴恩达机器学习笔记30-神经网络的反向传播算法(Backpropagation Algorithm)

    之前我们在计算神经网络预测结果的时候我们采用了一种正向传播方法,我们从第一层开始正向一层一层进行计算,直到最后一层的ℎ

  5. DOS窗口查看端口占用

    背景:最近用tomcat,一直访问不了,要账号密码登录,最后发现问题原因根本是tomcat的默认端口号8080被占用了,下面介绍如何通过dos窗口找到占用端口的进程. 方法: 打开DOS窗口,输入ne ...

  6. 厉害了,Spring Cloud for Alibaba 来了!

    最近,Spring Cloud 发布了 Spring Cloud Alibaba 首个预览版本:Spring Cloud for Alibaba 0.2.0. 大家都好奇,这和阿里巴巴有什么关系?莫非 ...

  7. TypeScript基础类型,类实例和函数类型声明

    TypeScript(TS)是微软研发的编程语言,是JavaScript的超集,也就是在JavaScript的基础上添加了一些特性.其中之一就是类型声明. 一.基础类型 TS的基础类型有 Boolea ...

  8. 关于 Abp 替换了 DryIoc 框架之后的问题

    在之前有些过一篇文章 <使用 DryIoc 替换 Abp 的 DI 框架> ,在该文章里面我尝试通过以替换 IocManager 内部的 IContainer 来实现使用我们自己的 DI ...

  9. intellij idea maven project 无法显示dependencies

    Intellj 自动载入Mave依赖是一个很人性化的功能,但不排除有时候会碰到问题,导致pom文件修改却没有触发自动重新载入的动作或者加载中途出现弱网的情况中断载入的,此时需要手动强制更新依赖. 如下 ...

  10. Number(),parseInt(),parseFloat(),Math.round(),Math.floor(),Math.ceil()对比横评

    首先,这些处理方法可分为三类. 1,只用来处理数字取整问题的:Math.round(),Math.floor(),Math.ceil(): 2,专门用于把字符串转化成数值:parseInt(),par ...