当前位置: 首页 > news >正文

93 # 实现 express 错误处理中间件

上一节实现了 express 的中间件,这一节来实现错误处理中间件

执行某一步出错了,统一规定调用 next 传递的参数就是错误信息

先看 express 实现的demo

const express = require("express");
const app = express();app.use("/", (req, res, next) => {console.log("中间件1");// next();next("中间件1出错了");
});app.use("/", (req, res, next) => {console.log("中间件2");next();// next("中间件2出错了");
});app.use("/", (req, res, next) => {console.log("中间件3");next();// next("中间件3出错了");
});app.get("/",(req, res, next) => {console.log("路由1");next();},(req, res, next) => {res.end("出错了 *****");}
);app.listen(3000, () => {console.log(`server start 3000`);console.log(`在线访问地址:http://localhost:3000/`);
});

然后去访问:http://localhost:3000/

在这里插入图片描述

错误处理中间价,里面必须要有 4 个 参数(取函数的长度),放到栈的最底下

app.use((err, req, res, next) => {res.end(err);
})

在这里插入图片描述

下面实现处理逻辑

router/index.js

const url = require("url");
const Route = require("./route");
const Layer = require("./layer");
const methods = require("methods");function Router() {// 维护所有的路由this.stack = [];
}Router.prototype.route = function (path) {// 产生 routelet route = new Route();// 产生 layer 让 layer 跟 route 进行关联let layer = new Layer(path, route.dispatch.bind(route));// 每个路由都具备一个 route 属性,稍后路径匹配到后会调用 route 中的每一层layer.route = route;// 把 layer 放到路由的栈中this.stack.push(layer);return route;
};methods.forEach((method) => {Router.prototype[method] = function (path, handlers) {// 1.用户调用 method 时,需要保存成一个 layer 当道栈中// 2.产生一个 Route 实例和当前的 layer 创造关系// 3.要将 route 的 dispatch 方法存到 layer 上let route = this.route(path);// 让 route 记录用户传入的 handler 并且标记这个 handler 是什么方法route[method](handlers);};
});Router.prototype.use = function (path, ...handlers) {// 默认第一个是路径,后面是一个个的方法,路径可以不传if (typeof path === "function") {handlers.unshift(path);path = "/";}// 如果是多个函数需要循环添加层for (let i = 0; i < handlers.length; i++) {let layer = new Layer(path, handlers[i]);// 中间件不需要 route 属性layer.route = undefined;this.stack.push(layer);}
};Router.prototype.handle = function (req, res, out) {console.log("请求到了");// 需要取出路由系统中 Router 存放的 layer 依次执行const { pathname } = url.parse(req.url);let idx = 0;let next = (err) => {// 遍历完后没有找到就直接走出路由系统if (idx >= this.stack.length) return out();let layer = this.stack[idx++];if (err) {console.log("统一对中间件跟路由错误处理");// 找错误处理中间件if (!layer.route) {// 如果是中间件自己处理layer.handle_error(err, req, res, next);} else {// 路由则跳过,继续携带错误向下执行next(err);}} else {// 需要判断 layer 上的 path 和当前请求路由是否一致,一致就执行 dispatch 方法if (layer.match(pathname)) {// 中间件没有方法可以匹配,不能是错误处理中间件if (!layer.route) {if (layer.handler.length !== 4) {layer.handle_request(req, res, next);} else {next();}} else {// 将遍历路由系统中下一层的方法传入// 加速匹配,如果用户注册过这个类型的方法在去执行if (layer.route.methods[req.method.toLowerCase()]) {layer.handle_request(req, res, next);} else {next();}}} else {next();}}};next();
};module.exports = Router;

layer.js

function Layer(path, handler) {this.path = path;this.handler = handler;
}Layer.prototype.match = function (pathname) {if (this.path === pathname) {return true;}// 如果是中间件,进行中间件的匹配规则if (!this.route) {if (this.path == "/") {return true;}// /aaaa/b 需要 /aaaa/ 才能匹配上return pathname.startsWith(this.path + "/");}return false;
};
Layer.prototype.handle_error = function (err, req, res, next) {if (this.handler.length === 4) {// 调用错误处理中间件return this.handler(err, req, res, next);}next(err); // 普通的中间件
};
Layer.prototype.handle_request = function (req, res, next) {this.handler(req, res, next);
};
module.exports = Layer;

route.js

const Layer = require("./layer");
const methods = require("methods");function Route() {this.stack = [];// 用来描述内部存过哪些方法this.methods = {};
}Route.prototype.dispatch = function (req, res, out) {// 稍后调用此方法时,回去栈中拿出对应的 handler 依次执行let idx = 0;console.log("this.stack----->", this.stack);let next = (err) => {// 如果内部迭代的时候出现错误,直接到外层的 stack 中err && out(err);// 遍历完后没有找到就直接走出路由系统if (idx >= this.stack.length) return out();let layer = this.stack[idx++];console.log("dispatch----->", layer.method);if (layer.method === req.method.toLowerCase()) {layer.handle_request(req, res, next);} else {next();}};next();
};
methods.forEach((method) => {Route.prototype[method] = function (handlers) {console.log("handlers----->", handlers);handlers.forEach((handler) => {// 这里的路径没有意义let layer = new Layer("/", handler);layer.method = method;// 做个映射表this.methods[method] = true;this.stack.push(layer);});};
});module.exports = Route;

测试demo

const express = require("./kaimo-express");
const app = express();app.use("/", (req, res, next) => {console.log("中间件1");next();// next("中间件1出错了");
});app.use("/", (req, res, next) => {console.log("中间件2");// next();next("中间件2出错了");
});app.use("/", (req, res, next) => {console.log("中间件3");next();// next("中间件3出错了");
});app.get("/",(req, res, next) => {console.log("路由1");next();},(req, res, next) => {res.end("出错了 *****");}
);// 错误处理中间价
app.use((err, req, res, next) => {console.log("错误处理中间价----->", err);res.end(err);
});app.listen(3000, () => {console.log(`server start 3000`);console.log(`在线访问地址:http://localhost:3000/`);
});

在这里插入图片描述

相关文章:

93 # 实现 express 错误处理中间件

上一节实现了 express 的中间件&#xff0c;这一节来实现错误处理中间件 执行某一步出错了&#xff0c;统一规定调用 next 传递的参数就是错误信息 先看 express 实现的demo const express require("express"); const app express();app.use("/", (re…...

PHP 创建 MySQL 表

目录 PHP 创建 MySQL 表 使用 MySQLi 和 PDO 创建 MySQL 表 实例 (MySQLi - 面向对象) 实例 (MySQLi - 面向过程) 实例 (PDO) PHP 创建 MySQL 表 一个数据表有一个唯一名称&#xff0c;并有行和列组成。 使用 MySQLi 和 PDO 创建 MySQL 表 CREATE TABLE 语句用于创建 MySQ…...

中兴R5300 G4服务器iSAC管理员zteroot密码遗失的重置方法及IPV6地址启用设置

本文讲解中兴R5300 G4服务器BMC带外iSAC管理员zteroot密码遗失&#xff0c;无法登录时如何对其进行密码重置&#xff0c;以及iSAC启用IPV6地址的方法。 一、重置中兴R5300 G4服务器iSAC管理员zteroot密码 1、通过SSH登录到iSAC&#xff0c;默认用户名&#xff1a;sysadmin&am…...

大数据分布式处理框架Hadoop

大数据是什么 大数据容量常以TB、PB、甚至EB为单位&#xff0c;远超传统数据库的承载能力&#xff0c;无论入库还是查询都出现性能瓶颈。 Hadoop是什么 Hadoop是开源的分布式计算技术框架&#xff0c;用于处理大规模数据和实现分布式存储。 Hadoop核心组件 HDFS&#xff08;…...

echarts学习总结

一、新建一个简单的Echarts 1、首先新建一个vue2的项目&#xff0c;项目中安装Echarts cnpm install echarts --save2、新建一个ref <template><div ref"myecharts" id"myecharts"></div> </template> 3、引入echarts <scri…...

与初至波相关的常见误解

摘要: 初至波是指检波器首次接收到的波. 对它的误解会使我们失去重要的信息. 1. 波从震源到检波器的传导过程 从震源产生波以后, 有些波通过地面直接传导到检波器, 这些称为直达波 (面波);有些在地层中传播,遇到两种地层的分界面时 产生波的反射,在原来地层中形成一种新波, …...

screenfull全屏、退出全屏、指定元素全屏的使用步骤

文章目录 页面全屏页面全屏完整代码 1.下载插件 建议下载指定版本5.1.0&#xff0c;不然可能有一个报错 npm install --save screenfull5.1.02.页面引入 import screenfull from "screenfull"页面全屏 3.在标签上绑定点击事件 <div click"handleFull"…...

问题 - 谷歌浏览器 network 看不到接口请求解决方案

谷歌浏览器 -> 设置 -> 重置设置 -> 将设置还原为其默认值 查看接口情况&#xff0c;选择 All 或 Fetch/XHR&#xff0c;勾选 Has blocked cookies 即可 如果万一还不行&#xff0c;卸载浏览器重装。 参考&#xff1a;https://www.cnblogs.com/tully/p/16479528.html...

Java:正则表达式的命名捕获组

命名捕获组格式 (?<year>.*)-(?<month>.*)-(?<date>.*)完整示例 package com.example.demo;import java.util.regex.Matcher; import java.util.regex.Pattern;public class RegexTests {public static void main(String[] args) {String text "2…...

ELK 处理 Spring Boot 日志

ELK 处理 Spring Boot 日志&#xff0c;妙啊&#xff01; 来源&#xff1a;ibm.com/developerworks/cn/java /build-elk-and-use-it-for-springboot -and-nginx/index.html ELK 简介 Logstash Elasticsearch Kibana ELK 实现方案 ELK 平台搭建 安装 Logstash 安装 Elas…...

No152.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…...

Flutter:类功能索引(全)

Flutter 类功能索引&#xff08;全&#xff09; 本文以表描述形式收录了Flutter中提供的各个类&#xff0c;旨在方便地进行查询相关组件。 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133415589 跳转&#xff1a;字母索引 A 组件名称描述Animat…...

电脑技巧:笔记本电脑升级固态硬盘的注意事项,看完你就懂了

目录 1、接口类型 2、接口速率 3、固态硬盘的尺寸 4、发热情况 5、总结 如今的固态硬盘价格越来越便宜了&#xff0c;甚至某品牌4TB的PCIe4.0 M.2还爆出过不到900元的“报恩价”&#xff0c;让不少小伙伴都动了扩容甚至囤货的心思。但对于笔记本电脑用户来说&#xff0c;升…...

TLS/SSL(一)科普之加密、签名和SSL握手

一 背景知识 感悟&#xff1a; 不能高不成低不就备注&#xff1a; 以下内容没有逻辑排版,仅做记录 https基础面经 ① 加密方式 说明&#xff1a; 单向和双向认证遗留&#xff1a; 如何用openssl从私钥中提取公钥? ② 互联网数据安全可靠条件 说明&#xff1a; 二者相…...

UVA-1374 旋转游戏 题解答案代码 算法竞赛入门经典第二版

GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 由于书上给了思路&#xff0c;所以做起来并不难。 即使超时&#xff0c;因为数据量不大&#xff08;1000个&#xff09;&#xff0c; 我们也可以直接打表直接返回结果。 但是如果想不打表完…...

logback.xml springboot 项目通用logback配置,粘贴即用,按日期生成

<configuration scan"false" scanPeriod"10 seconds"><!-- 定义日志存放的根目录 --><property name"log.dir" value"./logs" /><!-- 彩色日志依赖的渲染类 --><conversionRule conversionWord"clr&q…...

【AI视野·今日CV 计算机视觉论文速览 第256期】Thu, 28 Sep 2023

AI视野今日CS.CV 计算机视觉论文速览 Thu, 28 Sep 2023 Totally 96 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers SHACIRA: Scalable HAsh-grid Compression for Implicit Neural Representations Authors Sharath Girish, Abhinav Shriva…...

2023-9-28 JZ26 树的子结构

题目链接&#xff1a;树的子结构 import java.util.*; /** public class TreeNode {int val 0;TreeNode left null;TreeNode right null;public TreeNode(int val) {this.val val;}} */ public class Solution {public boolean HasSubtree(TreeNode root1,TreeNode root2) …...

ElementUI之首页导航+左侧菜单

文章目录 一、Mock.js1.1.什么是Mock.js1.2.安装与配置1.3使用 二、登录注册跳转2.1.在views中添加Register.vue2.2.在Login.vue中的methods中添加gotoRegister方法2.3.在router/index.js中注册路由 三、组件通信&#xff08;总线&#xff09;3.1 在main.js中添加内容3.2.在com…...

【Linux学习】04Linux实用操作

Linux&#xff08;B站黑马&#xff09;学习笔记 01Linux初识与安装 02Linux基础命令 03Linux用户和权限 04Linux实用操作 05-1Linux上安装部署各类软件 文章目录 Linux&#xff08;B站黑马&#xff09;学习笔记前言04Linux实用操作各类小技巧&#xff08;快捷键&#xff09;ct…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...