实现一个简易koa2(一)— 基础架构

news2024/11/6 9:54:23

Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。

底层实现

koa、express这些使用node环境作为服务端,其实底层都还是用的node的http模块实现的。

const http = require('http');

const server = http.createServer((req, res) => {res.end('hello world');
});

server.listen(3000); 

这样我们就完成了一个服务端的创建,访问http://localhost:3000/即可看到一个hello world。koa在此基础上进行了封装,方便我们对请求进行更加精细化的控制。

创建Application

 // application.js
const http = require('http')

class Application {constructor() {this.middleware = [];}callback(req, res) {this.middleware.forEach(fn => fn(req, res))}use(fn) {typeof fn === 'function' && this.middleware.push(fn);}listen(...args) {const server = http.createServer(this.callback.bind(this))return server.listen(...args)}
}

module.exports = Application; 

现在我们有了use、listen方法,请求进来时会执行use中传入的中间件方法,现在中间件传入的是(req,res),但koa入参是(ctx,next),next先不考虑。

接下来我们需要去创建ctx,我们先看下ctx的关键几个属性。

  • ctx.req: Node 的 request 对象

  • ctx.res: Node的 response 对象

  • ctx.request: koa 的 Request 对象

  • ctx.response: koa 的 Response 对象.

  • ctx.app: 应用程序实例引用

结合上面我们来定义一个context.js,在这之前需要先定义Request、Response对象,因为ctx引用了它们。

创建Request、Response

Request、Response对象是对node上的request、response进行了封装。我们可以直接通过它们对node上的request和response进行取值、赋值如:

request.header
请求头对象。

request.header=
设置请求头对象。

response.body
获取响应体。

response.body=
设置响应体 

koa中使用了getter/setter去获取和设置Request,Response上的属性。这样做相比直接去操作node上的request、response的好处是,开发者的所用获取、设置都需要先经过我们的getter/setter方法,这样我们就可以对获取属性时做一些封装返回,对设置属性值做一层验证,提前将不规范的值抛出错误。

// request.js
module.exports = {get header() {return this.req.headers;},set header(val) {this.req.headers = val;},
};

// response.js
module.exports = {get body() {return this._body;},set body(val) {this._body = val;this.res.end(val);},
}; 

接下来我们还需要加入context,也就是传入use中的方法的ctx实例。

创建上下文Context

Context 将 node 的 requestresponse 对象封装在一个单独的对象里面,其为编写 web 应用和 API 提供了很多有用的方法。 这些操作在 HTTP 服务器开发中经常使用,因此其被添加在上下文这一层,而不是更高层框架中,因此将迫使中间件需要重新实现这些常用方法。

// context.js
module.exports = {get header() {return this.request.headers;},set header(val) {this.request.headers = val;},get body() {return this.response.body;},set body(val) {this.response.body = val;},
}; 
// application.js
const http = require("http");
const request = require("./request");
const response = require("./response");
const context = require("./context");

class Application {constructor() {this.middleware = [];this.context = Object.create(context);this.request = Object.create(request);this.response = Object.create(response);}createContext(req, res) {const context = Object.create(this.context);const request = (context.request = Object.create(this.request));const response = (context.response = Object.create(this.response));context.app = request.app = response.app = this;context.req = request.req = response.req = req;context.res = request.res = response.res = res;request.ctx = response.ctx = context;request.response = response;response.request = request;return context;}callback(req, res) {const ctx = this.createContext(req, res);this.middleware.forEach((fn) => fn(ctx));}...
}

module.exports = Application; 

这样就实现了通过ctx取值,以及赋值的操作了,但是如果context通过这种对Response、Request上的方法重写来实现代理,显然是很麻烦的很麻烦,且不易维护。所以Koa2使用了delegate来实现对Response、Request的代理。

// context.js
const delegate = require("delegates");

const proto = {/** * 这里可以写一些context特有的方法,如错误处理 * 以及需要同时用到res和req的方法,如cookies的处理 */
};

delegate(proto, "response").access("body");

delegate(proto, "request").getter("headers");

module.exports = proto; 

至此,一个最最最最基本的koa能正常跑起来了。

const Koa = require("../src/application");
const app = new Koa();

app.use(async (ctx) => {ctx.body = "Hello World";
});

app.listen(3000); 

打开浏览器输入http://localhost:3000/,能看到Hello World。

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/352842.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从一致性角度考虑推荐冷启动长尾推荐问题(一)

前言:目前中长尾推荐的方法有很多,主流的方法有几类比如:1)在没有项目ID嵌入的情况下提高推荐模型的鲁棒性,2)利用有限的交互数据提高学习效率,如使用元学习方法;3)利用物品侧面信息,便于物品ID嵌入的初始化&#xff0…

如何将美国主机与电子邮件绑定

对于使用美国主机的网站所有者来说,将电子邮件与其主机服务绑定非常重要。这是因为绑定电子邮件可以帮助网站所有者更好地管理他们的网站和维护网站的安全,便于接收网站通知和警报、通过电子邮件管理网站以及更好地保护网站的安全。本文将就美国主机如何…

FileZilla Client(客户端)下载安装教程

FileZilla Client(客户端)下载安装教程 目录FileZilla Client(客户端)下载安装教程一、下载1.官网下载地址2.点击 Download FileZilla Client3.点击Download二、安装1.双击安装包2.点击 I Agree3.选择 “Anyone who uses this computer”4.全选(勾选桌面图标&#x…

javaEE 初阶 — 传输层 TCP 协议中的异常情况与面向字节流的粘包问题

文章目录1 粘包问题1.1 什么是粘包问题1.2 如何解决粘包问题2 异常情况TCP 的十个特性:确认应答机制 超时重传机制 连接管理机制 滑动窗口 流量控制与拥塞控制 延迟应答与捎带应答 1 粘包问题 1.1 什么是粘包问题 面向字节流引入了一个比较麻烦的粘包问题。 …

BXC6332A第二代智能头盔方案助力电动车市场,为安全保驾护航

随着2020年6月1日起,公安部交管局在全国开展“一盔一带”安全守护行动,摩托车、电动车驾驶人乘车人按照规定正确使用头盔,是保障司乘安全的一道重要屏障,据统计,摩托车、电动自行车驾乘人员死亡事故中约80%为颅脑损伤致…

基于RK3588的嵌入式linux系统开发(三)——Uboot镜像文件合成

本章uboot镜像文件的合成包括官网必备文件rkbin下载和uboot镜像文件合成两部分内容,具体分别如下所述。 (一)下载rkbin文件包 以上uboot编译生成的uboot镜像不能直接烧录到板卡中运行,需要与atf、bl31、ddr配置文件等必备文件合成…

自动化测试工具_Jmeter

【课程简介】 接口测试是测试系统组件间接口的一种测试,接口测试天生为高复杂性的平台带来高效的缺陷监测和质量监督能力,平台越复杂,系统越庞大,接口测试的效果越明显。在接口测试大行其道的今天,测试工具也愈发重要,Jmeter作为一款纯 Java 开发的测试…

【刷题笔记】--二分查找binarysearch

当给一个有序的数组,在其中查找某个数,可以考虑用二分查找。 题目1: 二分查找的思路: 设置left和right指针分别指向要查找的区间。mid指针指向这个区间的中间。比较mid指针所指的数与target。 如果mid所指的数小于target&…

C语言——自定义类型:结构体,枚举,联合(详解)

1.结构体 1.1结构体类型的基础知识 结构体类型是一些值的集合,这些值被称为成员变量,成员变量可以是不同类型的变量。 1.2结构体类型的声明 结构体的声明格式如下: struct tag//tag表示标签名 {member-list;//成员列表//由1或者多个成员组成…

Hadoop01【尚硅谷】

大数据学习笔记 大数据概念 大数据:指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 主要解决,海量数据的存储…

iOS开发AppleDeveloper中给别人授权开发者权限后,对方一直显示不了我的开发账号team

在iOS开发经常出现多人协作开发的情况。这时我们通常要发邮件邀请别的用户为开发者或者app管理就可以开发我们自己的项目了。但是这次我给别人授权开发者权限后,发现别人权限中没有证书相关权限如图:并且别人登录该账号后,在xcode中只有一个看…

【办公类-16-09】“2022下学期 大班运动场地分配表-跳过节日循环排序”(python 排班表系列)

样例展示:跳过节日的运动场地循环排序表(8个班级8组内容 下学期一共20周)背景需求:上学期做过一次大班运动场地安排,跳过节日。2023.2下学期运动场地排班(跳过节日)又来了。一、场地器械微调二、…

雅利安人有多强悍?灭掉三个文明古国,为何败在殷商的脚下

转自:雅利安人有多强悍?灭掉三个文明古国,为何败在中国脚下 (baidu.com)这个民族民风彪悍;这个民族曾一度将四大文明古国中的三个——古埃及、古印度、古巴比伦尽数消灭;这个民族甚至被称为“文明粉碎机”;…

EasyExcel的使用

这里写目录标题先导入依赖最简单的写最简单的读項目开发中的一些操作xml一定要默認放先导入依赖 <dependencies><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.7</version><…

lombok的原理 和 使用

原理Lombok能以简单的注解形式来简化java代码&#xff0c;提高开发人员的开发效率。其实并没有改变字节码文件的任何内容&#xff0c;只是简化的程序员编写代码的方式。不使用lombok&#xff1a;使用lombok&#xff1a;lombok常用注解Setter &#xff1a;注解在类或字段&#x…

【面试总结】Linux篇·操作及原理篇

【面试总结】Linux篇原理篇1.介绍一下inode2.说一下Linux系统的目录结构3.说一下Linux系统的文件类型4.如何在Linux上配置一个IP地址5.Linux负载是什么&#xff1f;6.Linux中的软链接和硬链接有什么区别&#xff1f;1.介绍一下inode 硬盘的最小存储单位是扇区(Sector)&#xf…

2自由度悬架LQR控制

目录 1 悬架系统 1.1 悬架结构示意图 1.2 悬架数学模型 1.3 路面激励 2.仿真分析 2.1simulink模型 2.2 仿真结果 2.3 结论 3. 总结 1 悬架系统 1.1 悬架结构示意图 1.2 悬架数学模型 其中&#xff1a;x1为悬架动扰度&#xff0c;x2为车身加速度&#xff0c;x3为轮胎…

红黑树的历史和由来。

一个数组&#xff0c;1,2,3,4,5,...n; 一共n个数字。1、直接查找想要查询第n个数字&#xff0c;直接搜索&#xff0c;就是n次查询。ps:那么问题来了&#xff0c;这样查询也太慢了&#xff0c;有什么改进的呢&#xff1f;2、二分查找这个时候&#xff0c;二分查找更快。不过就是…

python中的.nc文件处理 | 04 利用矢量边界提取NC数据

利用矢量边界提取.nc数据 import osimport numpy as np import pandas as pd import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature import seaborn as sns import geopandas as gpd import earthpy as et import xarray as xr # …

渲染有问题?怎么办?6种方法让你渲染无忧

简单点&#xff0c;解决问题的方式简单点。 日常工作中我们总会遇到各种各样的问题&#xff0c;比如渲不出图&#xff0c;速度太慢或效率太低&#xff0c;各种噪点和黑图等等&#xff0c;烦不胜烦&#xff0c;今天我就针对6个常见的问题给大家说下方法&#xff0c;一家之言仅供…