Skip to content

Commit 95e1ca6

Browse files
committed
feat: express
1 parent ff29145 commit 95e1ca6

File tree

1 file changed

+255
-0
lines changed

1 file changed

+255
-0
lines changed
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
---
2+
title: express
3+
author: 高红翔
4+
date: 2024-10-08 14:48:34
5+
categories:
6+
tags:
7+
---
8+
9+
### 基本使用
10+
11+
```js
12+
import express from "express"
13+
const app = express()
14+
app.use(
15+
function (req, res, next) {
16+
console.log("middlware 1")
17+
next()
18+
},
19+
function (req, res, next) {
20+
console.log("middlware 2")
21+
next("a")
22+
}
23+
)
24+
app.use(function (req, res, next) {
25+
console.log("middlware 3")
26+
next()
27+
})
28+
app.get("/user", function (req, res, next) {
29+
// console.log(1, req.a)
30+
console.log("222=>", 222)
31+
next()
32+
})
33+
app.use((err, req, res, next) => {
34+
res.end(err)
35+
})
36+
app.listen(3001)
37+
```
38+
39+
### 核心实现
40+
41+
#### application.js
42+
43+
> application.js 是框架的主入口,负责启动 HTTP 服务器并处理请求。
44+
45+
- **懒加载路由系统**`lazy_route` 方法确保在需要时才加载路由系统。
46+
47+
- **use 方法**:用于注册全局中间件。
48+
49+
- **listen 方法**:创建 HTTP 服务器,通过调用 `this.router.handle` 处理每个请求。如果没有匹配的路由,则调用 `done` 方法结束请求,返回错误信息。
50+
51+
```js
52+
import http from "http"
53+
import methods from "methods"
54+
import Router from "./router/index.js"
55+
56+
function Application() {}
57+
58+
Application.prototype.lazy_route = function () {
59+
if (!this.router) {
60+
this.router = new Router() // 将路由系统进行了懒加载处理(一般都是要加载的)
61+
}
62+
}
63+
Application.prototype.use = function () {
64+
this.lazy_route()
65+
this.router.use(...arguments) // 交给路由系统来处理
66+
}
67+
Application.prototype.listen = function (...args) {
68+
const server = http.createServer((req, res) => {
69+
function done() {
70+
// 如果路由系统中的层不存在则调用此方法来结束响应
71+
res.end(`Cannot ${req.method} ${req.url}`)
72+
}
73+
// 交给路由系统来做匹配,如果匹配不到就调用done
74+
this.router.handle(req, res, done)
75+
})
76+
server.listen(...args)
77+
}
78+
methods.forEach((method) => {
79+
Application.prototype[method] = function (path, ...handlers) {
80+
// 让路由系统处理逻辑
81+
this.lazy_route()
82+
this.router[method](path, handlers)
83+
}
84+
})
85+
86+
export default Application
87+
```
88+
89+
#### Router.js
90+
91+
> router.js 是路由系统的核心,管理路由栈(stack)并实现路由匹配逻辑。
92+
93+
- **路由注册**:为每个 HTTP 方法创建相应的路由,使用 `Layer` 类管理路径,并通过 `dispatch` 方法执行相应的路由处理函数。
94+
- **中间件注册**`use` 方法用于注册全局或特定路径的中间件。
95+
- **请求处理**`handle` 方法用于匹配请求路径和方法,逐层执行中间件和路由处理函数。如果存在错误,则调用错误处理中间件。
96+
97+
```js
98+
import url from "url"
99+
import methods from "methods"
100+
import Layer from "./Layer.js"
101+
import Route from "./route.js"
102+
function Router() {
103+
this.stack = []
104+
}
105+
methods.forEach((method) => {
106+
Router.prototype[method] = function (path, handlers) {
107+
// 调用类来管理路径
108+
let route = new Route()
109+
handlers.forEach((handler) => {
110+
route[method](handler)
111+
})
112+
let layer = new Layer(path, route.dispatch.bind(route))
113+
// 每个路由的层都有一个route属性,对应存放自己的真实路基的
114+
layer.route = route
115+
this.stack.push(layer)
116+
}
117+
})
118+
Router.prototype.use = function (path, ...handlers) {
119+
if (typeof path === "function") {
120+
handlers = [path, ...handlers] // path就是处理函数
121+
path = "/" // 如果没写路径就是 / 匹配所有的路径
122+
}
123+
handlers.forEach((handler) => {
124+
const layer = new Layer(path, handler)
125+
layer.route = undefined // 中间件没有路由这个对象
126+
this.stack.push(layer)
127+
})
128+
}
129+
Router.prototype.handle = function (req, res, out) {
130+
const { pathname, query } = url.parse(req.url, true)
131+
const method = req.method.toLowerCase()
132+
let idx = 0
133+
let next = (err) => {
134+
if (this.stack.length == idx) return out()
135+
let layer = this.stack[idx++] // 拿出第一个层
136+
if (err) {
137+
if (!layer.route) {
138+
// 有错误找中间件,而且 要找参数是4个的中间件
139+
if (layer.handler.length === 4) {
140+
layer.handler(err, req, res, next)
141+
} else {
142+
next(err) // 普通中间件继续带着错误向下走
143+
}
144+
} else {
145+
// 有错误但是是路由,要带着 错误继续往下走
146+
next(err)
147+
}
148+
} else {
149+
// 因为错误处理中间件定义在了 router.stack中 ,如果有err就去这个stack中查找错误处理中间件
150+
if (layer.match(pathname)) {
151+
if (layer.route) {
152+
// 路由
153+
if (layer.route.methods[req.method.toLowerCase()]) {
154+
// 需要匹配方法
155+
layer.handle_request(req, res, next) // route.dispatch
156+
} else {
157+
next() // 方法不一致直接向下走
158+
}
159+
} else {
160+
// 中间件无需匹配方法, 没有错误不能执行错误处理中间件
161+
if (layer.handler.length !== 4) {
162+
layer.handle_request(req, res, next) // route.dispatch
163+
} else {
164+
next()
165+
}
166+
}
167+
} else {
168+
next()
169+
}
170+
}
171+
}
172+
173+
next() // 默认在路由中筛查
174+
}
175+
176+
export default Router
177+
```
178+
179+
#### Layer.js
180+
181+
> layer.js 定义了路由和中间件的抽象层。每个路由或中间件对应一个 Layer 实例。
182+
183+
- **匹配路径**`match` 方法用于检查当前 `Layer` 是否匹配请求路径。
184+
185+
- **请求处理**`handle_request` 方法调用具体的处理函数。
186+
187+
```js
188+
// 路由中对应的层
189+
function Layer(path, handler) {
190+
this.path = path
191+
this.handler = handler
192+
}
193+
Layer.prototype.match = function (path) {
194+
if (this.path === path) {
195+
return true
196+
}
197+
if (!this.route) {
198+
// 中间件
199+
if (this.path === "/") {
200+
// 中间件是/都能匹配
201+
return true
202+
}
203+
return path.startsWith(this.path + "/")
204+
}
205+
return false
206+
}
207+
208+
Layer.prototype.handle_request = function (req, res, next) {
209+
return this.handler(req, res, next)
210+
}
211+
export default Layer
212+
```
213+
214+
#### Route.js
215+
216+
> route.js 负责管理每个特定路由的处理函数,并调度(dispatch)处理。
217+
218+
- **方法注册**:为每个路由绑定特定 HTTP 方法(如 `get``post`),并将处理函数存储在 `stack` 中。
219+
220+
- **调度处理**`dispatch` 方法根据请求方法依次执行对应的处理函数。
221+
222+
```js
223+
import methods from "methods"
224+
import Layer from "./Layer.js"
225+
function Route() {
226+
this.stack = []
227+
this.methods = {} // 用来描述这个route中有什么方法
228+
}
229+
methods.forEach((method) => {
230+
Route.prototype[method] = function (handler) {
231+
let layer = new Layer("里层的用户的逻辑不需要这个path", handler)
232+
layer.method = method
233+
this.methods[method] = true // {get:true}
234+
this.stack.push(layer)
235+
}
236+
})
237+
238+
Route.prototype.dispatch = function (req, res, out) {
239+
let idx = 0
240+
const next = (err) => {
241+
console.log("run")
242+
if (err) return out(err)
243+
if (idx === this.stack.length) return out()
244+
let layer = this.stack[idx++]
245+
if (req.method.toLowerCase() === layer.method) {
246+
// 用户绑定的方法
247+
layer.handle_request(req, res, next)
248+
} else {
249+
next()
250+
}
251+
}
252+
next()
253+
}
254+
export default Route
255+
```

0 commit comments

Comments
 (0)