什么是异常

做开发的基本都知道异常,像Android开发中常见的ANR异常、空指针异常,服务器开发中经常遇到的异常404,500异常,还有一些其他常见的异常,具体可见HTTP状态码

基本上这些异常可以总结为:已知异常未知异常

已知异常就是程序中能够预想到异常,比如:服务器接口开发中某个api接口需要5个参数,而用户传递的参数多余5个或者少于5个,这种错误就是已知错误。

未知异常就说程序中不能预想到的异常,比如:服务器接口开发中遇到了空指针而程序中又没有做相应处理就会抛出HTTP状态码为500的这种异常,这种就说未知异常。

为什么需要全局异常处理

当遇到异常时如果没有全局异常处理,一般是在相应的代码逻辑中添加异常捕捉(try ... catch)或者抛出(throw)处理。

这么做其实是有弊端的:

  1. 程序代码判断逻辑过长,可读性查,不方便后期维护。
  2. 代码耦合性高,每次出现异常都需要在不同的类、文件下写异常判断逻辑。

以上只是列举的几个弊端,为了解决以上的问题程序中添加全局异常的处理就很有必要了。

这里使用的是NodeJS+Koa2开发。在Koa中,中间件是无处不在,所以这里全局异常的处理也是通过中间件的方式去实现。

如何处理

1、明确是否需要抛出异常

在服务器接口开发中需要明确是生产环境还是开发环境

生产环境中如果出现异常需要将详细的异常信息上报同时将异常状态通过api返回给客户端处理

开发环境中如果出现异常则需要将详细的异常信息在开发工具的控制台显示,同时返回将异常状态通过api返回给客户端处理。

这里的区别就说生产环境开发环境,所以通过定义一个全局变量去判断即可。由于程序中全局变量可能不止一个,为了统一声明全局变量,我们将所有的全局变量放在一个文件中,统一去加载。

新建一个config.js,里面的environment:'dev'就是对环境声明的变量,这里dev表示开发环境prod表示生产环境

module.exports = {
// prod 表示生产环境
environment:'dev',
database:{
dbName:'book',
host:'localhost',
port:3306,
user:'用户名',
password:'密码',
},
// token 设置为1天
security:{
secretKey:"密钥,要记住不能弄丢了哦",
expiresIn:60*60*24
},
host:'http://localhost:3000/'
}

配置了全局变量之后,在init.js文件的InitManager类中定义静态方法:

/**
* 加载全局配置文件
* @param {''} path 当前路径
*/
static loadConfig(path = '') {
const configPath = path || process.cwd() + '/config/config.js'
const config = require(configPath)
global.config = config
}
/**
* 加载全局异常
*/
static loadHttpException(){
const errors = require('./http-exception')
global.errs = errors
}

最后在app.js中完成初始化。

const app = new Koa()
InitManager.loadConfig()
InitManager.loadHttpException()

定义全局变量之后就需要制定返回的api异常描述

2、定义异常的返回结果

在服务器接口开发中,一个异常的返回结果,通常包含有:

  • msg:异常描述
  • errorcode:自定义的异常状态码
  • code:网络请求的状态码

两个code的区别:

  • errorcode :自定义的错误码,配合code定位具体的异常。
  • code:网络请求的状态码,如403 权限受限,而权限受限的原因有很多种,比如未登录或者登录了但是权限不足,这时候可以结合自定义的错误码和异常描述准确明确告知用户出错的原因。

定义异常描述之后就需要去判断程序是已知异常还是未知异常。

3、明确是已知异常还是未知异常

已知异常:可以定义HttpException继承Error这个类,只要是出现这异常属于HttpException都属于已知异常。

http-exception.js

/**
* 默认的异常
*/
class HttpException extends Error{
constructor(msg='服务器异常',errorCode=10000, code=400){
super()
this.errorCode = errorCode
this.code = code
this.msg = msg
}
} /**
* 资源未找到提示
*/
class NotFound extends HttpException{
constructor(msg, errorCode) {
super()
this.msg = msg || '资源未找到'
this.errorCode = errorCode || 10000
this.code = 404
}
} module.exports = {
HttpException,
NotFound
}

环境变量声明了、异常也做了处理,那么如何监听全局异常呢?

4、全局异常监听

首先编写捕捉异常处理中间件catchError.js

const {HttpException} = require('../core/http-exception')

const catchError = async (ctx, next)=>{
try {
await next()
} catch (error) {
// 已知异常
const isHttpException = error instanceof HttpException
// 开发环境
const isDev = global.config.environment === 'dev'
// 在控制台显示未知异常信息:开发环境 不是HttpException 抛出异常
if(isDev && !isHttpException){
throw error
} /**
* 是已知错误,还是未知错误
* 返回:
* msg 错误信息
* error_code 错误码
* request 请求的接口路径
*/
if(isHttpException){
ctx.body = {
msg:error.msg,
error_code:error.errorCode,
request:`${ctx.method} ${ctx.path}`
}
ctx.status = error.code
}
else{
ctx.body = {
msg: '服务器出现了未知异常',
error_code: 999,
request:`${ctx.method} ${ctx.path}`
}
ctx.status = 500
}
}
} module.exports = catchError

然后在app.js中加载中间件

const catchError = require('./middlewares/exception')
const app = new Koa()
// 全局异常中间件监听、处理,放在所有中间件的最前面
app.use(catchError)
app.listen(3000)

以上就完成了全局异常的处理,接下来就是如何使用这个全局异常了。

5、出现异常后及时抛出异常

这里以资源未找到为例。在查询数据库中,有的时候会出现数据找不到情况,这是用就可以抛出资源未找到的异常。

models/book.js

 /**
* 获取书籍详情
* @param {书籍id} bid
*/
static async detail(bkid) {
const book =await Book.findOne({
where: {
bkid
}
})
if (!book) {
// 通过全局异常的方式,抛出资源未找到的错误
throw new global.errs.NotFound()
}
return book
}

咨询请加微信:轻撩即可。

全栈项目|小书架|服务器开发-Koa2 全局异常处理的更多相关文章

  1. 全栈项目|小书架|服务器开发-Koa2中间件机制洋葱模型了解一下

    KOA2 是什么? Koa是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小.更富有表现力.更健壮的基石. 通过利用 asyn ...

  2. 全栈项目|小书架|服务器开发-Koa2 连接MySQL数据库(Navicat+XAMPP)

    为什么使用数据库 为什么需要数据库?-知乎 相比与文件系统,数据库具有以下优势: 高效率:查找效率高 高可用:可数据库共享 安全性强:数据不能随意修改 选择哪个数据库 数据库可以分为关系型数据库和非关 ...

  3. 全栈项目|小书架|服务器开发-Koa2 参数校验处理

    为什么需要做参数校验 在开发中,无论是App开发还是服务器接口开发, 我们无法去预测用户传入的数据,因此参数(数据)校验是开发中不可或缺的一环. 例如像App的注册登录表单提交页面,就要做好多层的判断 ...

  4. 全栈项目|小书架|服务器开发-Koa全局路由实现

    什么是路由 路由就是具体的访问路径,指向特定的功能模块.一个api接口是由ip(域名)+端口号+路径组成,例如 :https://www.npmjs.com/package/koa-router就是一 ...

  5. 全栈项目|小书架|服务器开发-NodeJS 使用 JWT 实现登录认证

    通过这篇 全栈项目|小书架|服务器开发-JWT 详解 文章我们对JWT有了深入的了解,那么接下来介绍JWT如何在项目中使用. 安装 $ npm install jsonwebtoken 生成 Toke ...

  6. 全栈项目|小书架|服务器开发-NodeJS 项目分包

    唠嗑 参考的是慕课网七月老师的课程,七月的课质量真的挺高的,推荐一波.这次的小书架项目源码不会全部公开,因为用了七月老师课程的绝大部分代码.虽然代码不全,但是只要思路看得懂,代码实现就很简单了. 小书 ...

  7. 全栈项目|小书架|服务器开发-JWT 详解

    JWT 官方简介:Introduction to JSON Web Tokens 文章基本是官网内容的翻译,英文不错的同学可点击上面的链接直接看英文文档. 什么是 JWT JWT全称是JSON Web ...

  8. 全栈项目|小书架|服务器开发-NodeJS 中使用 Sequelize 操作 MySQL数据库

    安装 官网:https://sequelize.org/v5/manual/getting-started.html 安装sequelize及数据库连接驱动 npm install --save se ...

  9. 全栈项目|小书架|服务器端-NodeJS+Koa2实现首页图书列表接口

    通过上篇文章 全栈项目|小书架|微信小程序-首页水平轮播实现 我们实现了前端(小程序)效果图的展示,这篇文章来介绍服务器端的实现. 首页书籍信息 先来回顾一下首页书籍都有哪些信息: 从下面的图片可以看 ...

随机推荐

  1. [Note] Windows 10 Python 3.6.4 安装scrapy

    直接使用pip install安装时会在安装Twisted出错,以下主要是解决Twisted的安装问题 1. 安装wheel pip install wheel 2. 安装Twisted 在Pytho ...

  2. MongoDB 学习笔记之 索引

    索引: db.media.createIndex({"Tracklist": 1}) 1表示升序 -1表示降序 我们要着重看一下对数组创建索引的情况. 构建一个集合:db.medi ...

  3. ShutdownHook- Java 优雅停机解决方案

    想象一下,如果你现在刚好在 word 上写需求文档,电脑突然重启.等待开机完成,你可能会发现写了一个小时文档没有保存,就这么没了... 一个正在运行 Java 应用如果突然将其停止,影响不止数据丢失, ...

  4. 50个实用的jq代码段整理

    个人博客: http://mcchen.club   1. 如何创建嵌套的过滤器:   //允许你减少集合中的匹配元素的过滤器,   //只剩下那些与给定的选择器匹配的部分.在这种情况下,   //查 ...

  5. Java读源码之Thread

    前言 JDK版本:1.8 阅读了Object的源码,wait和notify方法与线程联系紧密,而且多线程已经是必备知识,那保持习惯,就从多线程的源头Thread类开始读起吧.由于该类比较长,只读重要部 ...

  6. Windows 10 删除C盘的用户,恢复技巧

    起因 入域不成功,然后强制删除了C盘 Users里面 账户 然后再进行入域的时候就入域不成功了,如果再进行登录就会提示 无法登录到你的账户 通常可以通过从你的账户注销,然后重新登录解决此问题 如果不立 ...

  7. 清除SQL Server Management Studio的最近服务器列表

    C:\Users\dell\AppData\Roaming\Microsoft\SQL Server Management Studio\12.0\SqlStudio.bin

  8. 一个纯CSS实现的卡片翻转效果

    先上代码 <div id="box"> <div class="front">正面</div> <div class= ...

  9. python编程基础之二十六

    偏函数:当一个函数有大量的参数时候,调用时候非常不方便,于是就可以用偏函数解决,将一些参数固定(默认值),达到简化函数调用的目的 使用偏函数需要导入functools import functools ...

  10. SQL SERVER数据库,按年、月、日、时、分、秒计算两个时间字段之间的间隔时间样例

    使用DATEDIFF(取值,时间字段1,时间字段2) 举例: SELECT DATEDIFF(YEAR,DRYSJ,DCYSJ),* FROM YXHIS2019..TBZYBR2019 --SQL ...