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

Deno中间件框架开发:从零实现Koa.js风格的洋葱模型 | Deno进阶开发笔记

Deno中间件框架开发:从零实现Koa.js风格的洋葱模型 | Deno进阶开发笔记

【免费下载链接】deno_note《Deno进阶开发笔记》 (不定时更新) 🌶🌶🌶项目地址: https://gitcode.com/gh_mirrors/de/deno_note

Deno作为新一代JavaScript/TypeScript运行时,凭借其安全性、模块化设计和原生TypeScript支持,正逐渐成为后端开发的新选择。本文将带你从零开始,在Deno环境中实现一个类似Koa.js的中间件框架,深入理解洋葱模型的工作原理,并掌握Deno生态下的Web开发核心技术。

为什么选择Deno开发中间件框架?

Deno自2020年正式发布以来,已经发展成为一个成熟的运行时环境。与Node.js相比,它具有以下优势:

  • 原生TypeScript支持:无需额外配置即可直接运行TypeScript代码
  • 安全的默认行为:所有文件系统和网络访问都需要显式授权
  • 内置工具链:包含格式化、测试、文档生成等开发工具
  • 现代标准库:基于最新的Web标准,支持Fetch API、Web Streams等

这些特性使得Deno特别适合构建轻量级、高性能的Web框架。在本项目中,我们将利用Deno的这些优势,实现一个简洁而强大的中间件框架。

洋葱模型:中间件的核心原理

中间件是现代Web框架的核心概念,而洋葱模型则是Koa.js等框架最具特色的设计。简单来说,洋葱模型允许中间件在请求处理前后都执行代码,形成"层层包裹"的处理流程。

洋葱模型的优势在于:

  • 灵活的请求/响应处理:中间件可以在请求到达时执行前置操作,在响应发送前执行后置操作
  • 统一的错误处理:异常可以在任何中间件层被捕获和处理
  • 模块化组合:不同功能可以封装为独立中间件,按需组合使用

从零实现Deno中间件框架

1. 项目结构与准备

首先,克隆项目仓库并进入工作目录:

git clone https://gitcode.com/gh_mirrors/de/deno_note cd de/deno_note

我们的中间件框架主要包含以下核心文件:

  • demo/web/application.ts:应用主类,负责管理中间件和启动服务
  • demo/web/compose.ts:实现洋葱模型的核心函数
  • demo/web/context.ts:封装请求/响应上下文

2. 实现洋葱模型的核心compose函数

compose函数是洋葱模型的核心,它负责按顺序执行中间件并控制流程。以下是实现代码:

export const compose = function (middleware: Function[]) { if (!Array.isArray(middleware)) { throw new TypeError('Middleware stack must be an array!'); } return function(ctx: object, next?: Function) { let index = -1; return dispatch(0); function dispatch(i: number) { if (i < index) { return Promise.reject(new Error('next() called multiple times')); } index = i; let fn: any = middleware[i]; if (i === middleware.length) { fn = next; } if (!fn) { return Promise.resolve(); } try { return Promise.resolve(fn(ctx, () => { return dispatch(i + 1); })); } catch (err) { return Promise.reject(err); } } }; }

这个函数接收一个中间件数组,返回一个函数,该函数接收上下文对象和下一个中间件函数。通过递归调用dispatch函数,实现中间件的层层调用和回溯。

3. 创建Application类管理中间件

Application类是框架的入口点,负责注册中间件、创建HTTP服务器和处理请求:

import { Context, SafeContext } from "./context.ts"; import { Server } from "./../server/mod.ts"; import { compose } from "./compose.ts"; class Application { private _middlewares: Function[]; private _server: Server; constructor() { this._middlewares = []; this._server = new Server(); } public use(fn: Function): void { this._middlewares.push(fn); } public async listen(opts: Deno.ListenOptions, fn: Function) { const that = this; const server = this._server; server.createServer(async function(ctx: Context) { const middlewares = that._middlewares; try { const sctx = new SafeContext(ctx); await compose(middlewares)(sctx); const body = sctx.res.getBody(); if (!(body && typeof body === "string" && body.length > 0)) { sctx.res.setBody("404 Not Found!"); } await ctx.res.flush(); } catch (err) { that._onError(err, ctx); } }); server.listen(opts, fn); } private async _onError(err: Error, ctx: Context) { console.log(err); if (ctx instanceof Context) { ctx.res.setBody(err.stack || 'Server Error'); ctx.res.setStatus(500); await ctx.res.flush(); } else { Deno.exit(1); } } } export { Application };

在listen方法中,我们创建了HTTP服务器,并在请求到来时使用compose函数执行所有注册的中间件。

4. 封装请求/响应上下文

Context类封装了HTTP请求和响应对象,提供了简洁的API供中间件使用:

// 简化版Context类示例 export class Context { public req: Request; public res: Response; constructor(req: Request, res: Response) { this.req = req; this.res = res; } // 提供便捷方法 public set status(code: number) { this.res.status = code; } public set body(value: string) { this.res.body = value; } }

使用示例:创建第一个Deno中间件应用

现在,让我们使用刚刚实现的框架创建一个简单的Web应用:

import { Application } from './demo/web/application.ts'; const app = new Application(); // 日志中间件 app.use(async (ctx, next) => { const start = Date.now(); await next(); const ms = Date.now() - start; console.log(`${ctx.req.method} ${ctx.req.url} - ${ms}ms`); }); // 响应中间件 app.use(async (ctx) => { ctx.res.setBody('Hello Deno Middleware!'); ctx.res.setStatus(200); }); // 启动服务器 app.listen({ port: 8000 }, () => { console.log('Server running on port 8000'); });

运行这个应用:

deno run --allow-net demo/web/example.ts

访问http://localhost:8000,你将看到"Hello Deno Middleware!"的响应,同时控制台会输出请求日志。

进阶技巧:中间件的高级用法

1. 错误处理中间件

利用洋葱模型的特性,我们可以创建一个全局错误处理中间件:

app.use(async (ctx, next) => { try { await next(); } catch (err) { ctx.res.setStatus(500); ctx.res.setBody(`Server Error: ${err.message}`); } });

2. 路由中间件

我们可以实现一个简单的路由中间件,根据URL路径分发请求:

function router() { const routes: { path: string, handler: Function }[] = []; return { get(path: string, handler: Function) { routes.push({ path, handler }); }, middleware: async (ctx, next) => { const route = routes.find(r => r.path === ctx.req.url); if (route) { await route.handler(ctx); } else { await next(); } } }; } // 使用路由 const r = router(); r.get('/hello', async (ctx) => { ctx.res.setBody('Hello Router!'); }); app.use(r.middleware);

3. 静态文件服务中间件

实现一个提供静态文件服务的中间件:

async function staticMiddleware(ctx: any, next: Function) { const publicDir = './demo/web_static/public'; const path = ctx.req.url === '/' ? '/index.html' : ctx.req.url; try { const file = await Deno.readFile(`${publicDir}${path}`); ctx.res.setBody(file); // 设置适当的Content-Type // ... } catch { await next(); } } app.use(staticMiddleware);

总结与扩展

通过本文的学习,我们从零开始实现了一个基于Deno的中间件框架,深入理解了洋葱模型的工作原理。这个框架虽然简单,但包含了现代Web框架的核心思想。

你可以通过以下方式扩展这个框架:

  • 添加更多便捷的上下文方法
  • 实现更强大的路由系统,支持参数和通配符
  • 添加模板引擎支持
  • 实现中间件的级联和嵌套

Deno生态系统正在快速发展,这个中间件框架只是Deno强大能力的一个缩影。希望本文能帮助你更好地理解Deno和中间件架构,为你的下一个项目提供灵感!

项目完整代码可以在demo/web/目录下找到,包含了更多高级特性和示例。

【免费下载链接】deno_note《Deno进阶开发笔记》 (不定时更新) 🌶🌶🌶项目地址: https://gitcode.com/gh_mirrors/de/deno_note

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.jsqmd.com/news/1393134/

相关文章:

  • 2026年北京救护车转运梳理:康士恩等机构核心信息汇总 - 拜了拜了
  • Bow Optics入门:用Lens和Prism优雅操作不可变数据
  • 如何快速免费导出全平台个人数据:InfoSpider 零基础使用指南
  • AI+FFmpeg:用自然语言实现视频批量处理的自动化革命
  • 武汉配眼镜推荐,验光不专业再贵也白搭,五家验光对比 - 配眼镜新资讯
  • 稳定的DOO算力质押系统DAPP合约底层逻辑
  • Deno全局API详解:浏览器兼容与原生功能一网打尽
  • 跨平台开发神器Hunter:iOS/Android/Raspberry Pi环境配置教程
  • Rune.js高级技巧:自定义SVG节点注入与扩展库功能的方法
  • 长沙 AI 小班课适合谁?先看这 5 条再决定要不要报名
  • E4GL30S1NT API密钥配置教程:解锁全部高级功能
  • Spring Boot分布式定时任务实践:基于ShedLock与XXL-JOB的架构演进
  • 2026年苏州口碑最好的旅行社前十:杜绝强制消费,暑期外地游客参团实力! - 跟我去旅游
  • 猫抓插件一学就会:网页视频、音频资源一网打尽的完整指南
  • 告别闪退与卡顿:FusionFix修复补丁让GTA4老游戏在新电脑上重生
  • LunaTranslator 实战指南:3 步让视觉小说实时翻译跑起来,配置避坑一步到位
  • 哈尔滨闲置香奈儿包包别乱卖!选对渠道,回收价格直接翻一截 - 日常前沿快讯
  • 微信防撤回补丁实测手记:RevokeMsgPatcher 让被撤回的消息再也逃不掉
  • LLM推理服务商业化成本收益计算:从Kimi K3案例拆解盈利模型
  • 宋北京 - 每日快报资讯
  • draw.io桌面版完整指南:免费开源的跨平台绘图神器,3分钟画出第一张流程图
  • 解决Flutter文本内联图片难题:RealRichText的诞生与技术解析
  • 免费批量下载 LRC 歌词的完整指南:163MusicLyrics 30 分钟从入门到熟练
  • PhotoGIMP完整上手指南:免费补丁让GIMP 3.0对齐Photoshop快捷键与工作区布局
  • 2026年广州**自考助学点有哪些?靠不靠谱? - 一直爱学习的小花猫
  • 什么是PCB多层板仿真?教你读懂高速设计
  • 旧Mac如何免费升级最新系统?OpenCore Legacy Patcher让2008年以来的老设备重获新生
  • EtherGhost完整功能解析:从JSP支持到反弹Shell的全方位管理方案
  • Kuker与Redux完美结合:监控状态流转的实战指南
  • Noisy Nodes性能优化指南:提升Unity Shader Graph噪声渲染效率的5个方法