全栈项目|小书架|服务器开发-Koa2 全局异常处理

什么是异常

做开发的基本都知道异常,像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
 }

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

原文地址:https://www.cnblogs.com/gdragon/p/11829491.html

时间: 2024-08-30 11:23:03

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

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

KOA2 是什么? Koa是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小.更富有表现力.更健壮的基石. 通过利用 async函数,Koa帮你丢弃回调函数,并有力地增强错误处理. Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序. 为什么产生? 笔者对这几个框架都不熟,这里就不误人子弟了.可以看看下面一些大佬的介绍. Koa是由Express的原班人马打造,那么他们为什么不将

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

什么是路由 路由就是具体的访问路径,指向特定的功能模块.一个api接口是由ip(域名)+端口号+路径组成,例如 :https://www.npmjs.com/package/koa-router就是一个路由,指向了koa-router的npm页面. 为什么需要 koa-router 路由 当然不需要koa-router也能实现路由功能,通过ctx.request.path去指定路径实现.例子如下: const koa = require('koa2') const app = new koa()

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

通过上篇文章 全栈项目|小书架|微信小程序-首页水平轮播实现 我们实现了前端(小程序)效果图的展示,这篇文章来介绍服务器端的实现. 首页书籍信息 先来回顾一下首页书籍都有哪些信息: 从下面的图片可以看出目前一本图书信息主要有: 图片字段 名称字段 作者字段 出版社字段 除了以上前端页面中可见的信息外,在服务器开发中还需要给每一条记录(数据)都加上下面的几个字段: 创建时间字段 更新时间字段 删除时间字段 最后完成的数据库表如下: ps:由于数据库是直接导入的,之前的数据库是没有时间字段的,所以前

全栈项目|小书架|服务器端-NodeJS+Koa2 实现书籍详情接口

通过上篇文章 全栈项目|小书架|微信小程序-首页水平轮播实现 我们实现了前端(小程序)效果图的展示,这篇文章来介绍服务器端的实现. 书籍详情分析 书籍详情页面如下: 从上图可以分析出详情页面大概有以下几个接口: 获取书籍详情信息 获取用户对书籍的喜欢状态接口 喜欢/不喜欢书籍接口 获取评论列表 写评论接口 以上的接口,有的数据可以直接从已存在的数据表中去获取,比如:书籍详情信息,而其他新接口就需要创建对应的model,然后根据model创建相应的数据表. 比如 用户对书籍的喜欢操作,可以创建li

全栈项目|小书架|服务器端-NodeJS+Koa2 实现点赞功能

效果图 接口分析 通过上面的效果图可以看出,点赞入口主要是在书籍的详情页面. 而书籍详情页面,有以下几个功能是和点赞有关的: 获取点赞状态 点赞 取消点赞 所以项目中理论上与点赞相关的接口就以上三个. 点赞 model 的设计 既然明确了接口数量,那么下一步就是设计接口对应的model,通过model生成表格like,里面存放点赞数据. 那么需要存在哪些点赞数据呢? 这里简单分析后,记录一条点赞信息只需要保存以下的信息即可: 点赞 id 书籍 id 用户 id created_at delete

全栈项目|小书架|小程序端-评论功能实现

效果图 发布评论 发布评论的入口在图书详情页面,点击 写评论 按钮之后跳转到发布评论页面. wxml布局比较简单了,目前还没有添加图片评论功能,也没有子评论功能,所以伪代码就比较简单了: <view class="comment-container"> <!-- book name --> <view class="book-name"> <text>{{bookInfo.name}}</text> <

《从零开始做一个MEAN全栈项目》(1)

欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 在本系列的开篇,我打算讲一下全栈项目开发的优势,以及MEAN项目各个模块的概览. 为什么选择全栈开发?     对于初学者来说,学习一门新的语言和技术的体验总是让人愉快的,也会满足于掌握了一些新的东西并且解决了一些实际问题.在一个小组中采用全栈开发时,你可以更加有效地把握项目全局概念,这也有利于让你了解项目中的不同模块以及它们之间是如何协同工作的.你会对你们的产品中他人的贡献更加清晰,你也就了解了这款产品如何

《从零开始做一个MEAN全栈项目》(2)

欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习.   上一节简单介绍了什么是MEAN全栈项目,这一节将简要介绍三个内容:(1)一个通用的MEAN项目的技术架构,(2)为什么我们要打造单页应用,(3)本系列项目的技术架构和开发计划.希望通过这三个问题,我们能够对本项目产生一个全局视角. 实现一个常见的MEAN全栈项目的核心就是RESTful API.这个接口通常是用MongoDB, Express, Node.js实现的,而单页应用(SPA)由AngularJ

VueCli3.0全栈项目-资金管理系统带权限(node/element/vue)

课程简介:通过本系列课程,可以快速的掌握全栈开发流程, 包括node.js的接口搭建, vue前端项目的构建, element-ui视图的构建. 一套应有尽有的课程! 课程目录:1.Vue全栈-最终成果展示.mp42.Node接口搭建-express搭建服务器.mp43.Node接口搭建-连接MongoDB数据库.mp44.Node接口搭建-搭建路由和数据模型.mp45.Node接口搭建-搭建注册接口并存储数据.mp46.Node接口搭建-使用全球公认头像gravatar.mp47.Node接口