什么是异常

做开发的基本都知道异常,像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. [JavaScript] 《JavaScript高级程序设计》笔记

    1.||   和 && 这两个逻辑运算符和c#是类似的,都是惰性的计算 a() || b()  若a()为真返回a()的结果,此时b()不计算: a()为假则返回b() a() &am ...

  2. scalikejdbc 学习笔记(1)

    build.sbt: import sbt._ import Process._ import Keys._ EclipseKeys.createSrc := EclipseCreateSrc.Def ...

  3. Video/audio标签的一些基础使用心得

    常用方法 .play():用于音频视频的播放 .pause():用于音频视频的暂停 常用属性 <audio src="Batmobile Battle Mode Reveal Musi ...

  4. vs2019下载和更新速度非常慢的解决方案

    纵观全网,就两种解决方案 1.取消网络适配器里面的IPV6的给勾选[我试过,无效,但是有些网友说是有效果,也不知道是咋回事] 2.修改host.[本人亲测有效果,速度从5kb到5M左右,但是无法跑满宽 ...

  5. Rust入坑指南:常规套路

    搭建好了开发环境之后,就算是正式跳进Rust的坑了,今天我就要开始继续向下挖了. 由于我们初来乍到 ,对Rust还不熟悉,所以我决定先走一遍常规套路. 变不变的变量 学习一门语言第一个要了解的当然就是 ...

  6. redis在mac上的下载安装

    redis官网下载压缩包: 在终端进入下载后的目录,然后: 解压:tar zxvf redis-5.0.5.tar.gz 移动到:sudo mv redis-5.0.5 /usr/local 切换到: ...

  7. k8s中负载均衡器【ingress-nginx】部署

    在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的.为了使外部的应用能够访问集群内的服务,在Kubernetes 目前 提供了以下几种方案: Node ...

  8. Springboot2.x + ShardingSphere 实现分库分表

    之前一篇文章中我们讲了基于Mysql8的读写分离(文末有链接),这次来说说分库分表的实现过程. 概念解析 垂直分片 按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用. 在拆分之前 ...

  9. 全面系统Python3入门+进阶课程 ✌✌

    全面系统Python3入门+进阶课程 (一个人学习或许会很枯燥,但是寻找更多志同道合的朋友一起,学习将会变得更加有意义✌✌) 无论是大数据.人工智能还是机器学习,Python都是最热门的首选语言 ,这 ...

  10. vue中 props 多层组件嵌套传值

    如:三层嵌套. 父组件=>子组件=>孙子 1. 父组件引用子组件component11 , isShow传值给子组件component11 2. 子组件用  props 接受父组件的值, ...