什么是异常

做开发的基本都知道异常,像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. Mysql高手系列 - 第19篇:mysql游标详解,此技能可用于救火

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第19篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...

  2. 面试官:你有m个鸡蛋,如何用最少的次数测出鸡蛋会在哪一层碎?

    假设你面前有一栋n层的大楼和m个鸡蛋,假设将鸡蛋从f层或更高的地方放扔下去,鸡蛋才会碎,否则就不会.你需要设计一种策略来确定f的值,求最坏情况下扔鸡蛋次数的最小值. leetcode原题链接 乍一看这 ...

  3. MongoDB 学习笔记之 基本CRUD

    Mongo 命令: show databases/dbs; use test; show tables/collections; db.help() db.createCollection('user ...

  4. 13.Django基础之django分页

    一.Django的内置分页器(paginator) view from django.shortcuts import render,HttpResponse # Create your views ...

  5. Python读取excel 数据

    1.安装xlrd 2.官网 通过官网来查看如何使用python读取Excel,python excel官网: http://www.python-excel.org/ 实例: (1)Excel内容 把 ...

  6. BT面板安装php报错configure: error: C preprocessor “/lib/cpp” fails sanity check

    使用宝塔面板安装扩展时已经显示添加安装成功了,待我刷新浏览器之后没有安装成功.看了一下执行日志. 缺少必要的C++库,如下命令重装解决. yum reinstall glibc-headers gcc ...

  7. js对数组、对象的深拷贝、复制

    基本类型的数据是存放在栈内存中的,而引用类型的数据是存放在堆内存中的 基本类型:Number Boolean undefined String Null 引用类型:Object Function js ...

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

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

  9. SQL创建和调用有默认值的存储过程

    先创建一个有默认值的存储过程 create procedure usp_unpass ), --有默认值的参数放到最后 as select @score go 该存储过程有2个参数 ,其中@score ...

  10. Unity 登录白屏或者黑屏

    如果有一天,突然,你的Unity抽风了,登录界面白屏或者黑屏,不要急着重装.我重装了3次,第四次我再也忍不住了,终于出手了. 找到 C:\Users\hasee\AppData\Roaming\Uni ...