基本使用
import express from "express"
const app = express()
app.use(
function (req, res, next) {
console.log("middlware 1")
next()
},
function (req, res, next) {
console.log("middlware 2")
next("a")
}
)
app.use(function (req, res, next) {
console.log("middlware 3")
next()
})
app.get("/user", function (req, res, next) {
// console.log(1, req.a)
console.log("222=>", 222)
next()
})
app.use((err, req, res, next) => {
res.end(err)
})
app.listen(3001)
核心实现
application.js
application.js 是框架的主入口,负责启动 HTTP 服务器并处理请求。
懒加载路由系统:
lazy_route
方法确保在需要时才加载路由系统。use 方法:用于注册全局中间件。
listen 方法:创建 HTTP 服务器,通过调用
this.router.handle
处理每个请求。如果没有匹配的路由,则调用done
方法结束请求,返回错误信息。
import http from "http"
import methods from "methods"
import Router from "./router/index.js"
function Application() {}
Application.prototype.lazy_route = function () {
if (!this.router) {
this.router = new Router() // 将路由系统进行了懒加载处理(一般都是要加载的)
}
}
Application.prototype.use = function () {
this.lazy_route()
this.router.use(...arguments) // 交给路由系统来处理
}
Application.prototype.listen = function (...args) {
const server = http.createServer((req, res) => {
function done() {
// 如果路由系统中的层不存在则调用此方法来结束响应
res.end(`Cannot ${req.method} ${req.url}`)
}
// 交给路由系统来做匹配,如果匹配不到就调用done
this.router.handle(req, res, done)
})
server.listen(...args)
}
methods.forEach((method) => {
Application.prototype[method] = function (path, ...handlers) {
// 让路由系统处理逻辑
this.lazy_route()
this.router[method](path, handlers)
}
})
export default Application
Router.js
router.js 是路由系统的核心,管理路由栈(stack)并实现路由匹配逻辑。
- 路由注册:为每个 HTTP 方法创建相应的路由,使用
Layer
类管理路径,并通过dispatch
方法执行相应的路由处理函数。 - 中间件注册:
use
方法用于注册全局或特定路径的中间件。 - 请求处理:
handle
方法用于匹配请求路径和方法,逐层执行中间件和路由处理函数。如果存在错误,则调用错误处理中间件。
import url from "url"
import methods from "methods"
import Layer from "./Layer.js"
import Route from "./route.js"
function Router() {
this.stack = []
}
methods.forEach((method) => {
Router.prototype[method] = function (path, handlers) {
// 调用类来管理路径
let route = new Route()
handlers.forEach((handler) => {
route[method](handler)
})
let layer = new Layer(path, route.dispatch.bind(route))
// 每个路由的层都有一个route属性,对应存放自己的真实路基的
layer.route = route
this.stack.push(layer)
}
})
Router.prototype.use = function (path, ...handlers) {
if (typeof path === "function") {
handlers = [path, ...handlers] // path就是处理函数
path = "/" // 如果没写路径就是 / 匹配所有的路径
}
handlers.forEach((handler) => {
const layer = new Layer(path, handler)
layer.route = undefined // 中间件没有路由这个对象
this.stack.push(layer)
})
}
Router.prototype.handle = function (req, res, out) {
const { pathname, query } = url.parse(req.url, true)
const method = req.method.toLowerCase()
let idx = 0
let next = (err) => {
if (this.stack.length == idx) return out()
let layer = this.stack[idx++] // 拿出第一个层
if (err) {
if (!layer.route) {
// 有错误找中间件,而且 要找参数是4个的中间件
if (layer.handler.length === 4) {
layer.handler(err, req, res, next)
} else {
next(err) // 普通中间件继续带着错误向下走
}
} else {
// 有错误但是是路由,要带着 错误继续往下走
next(err)
}
} else {
// 因为错误处理中间件定义在了 router.stack中 ,如果有err就去这个stack中查找错误处理中间件
if (layer.match(pathname)) {
if (layer.route) {
// 路由
if (layer.route.methods[req.method.toLowerCase()]) {
// 需要匹配方法
layer.handle_request(req, res, next) // route.dispatch
} else {
next() // 方法不一致直接向下走
}
} else {
// 中间件无需匹配方法, 没有错误不能执行错误处理中间件
if (layer.handler.length !== 4) {
layer.handle_request(req, res, next) // route.dispatch
} else {
next()
}
}
} else {
next()
}
}
}
next() // 默认在路由中筛查
}
export default Router
Layer.js
layer.js 定义了路由和中间件的抽象层。每个路由或中间件对应一个 Layer 实例。
匹配路径:
match
方法用于检查当前Layer
是否匹配请求路径。请求处理:
handle_request
方法调用具体的处理函数。
// 路由中对应的层
function Layer(path, handler) {
this.path = path
this.handler = handler
}
Layer.prototype.match = function (path) {
if (this.path === path) {
return true
}
if (!this.route) {
// 中间件
if (this.path === "/") {
// 中间件是/都能匹配
return true
}
return path.startsWith(this.path + "/")
}
return false
}
Layer.prototype.handle_request = function (req, res, next) {
return this.handler(req, res, next)
}
export default Layer
Route.js
route.js 负责管理每个特定路由的处理函数,并调度(dispatch)处理。
方法注册:为每个路由绑定特定 HTTP 方法(如
get
、post
),并将处理函数存储在stack
中。调度处理:
dispatch
方法根据请求方法依次执行对应的处理函数。
import methods from "methods"
import Layer from "./Layer.js"
function Route() {
this.stack = []
this.methods = {} // 用来描述这个route中有什么方法
}
methods.forEach((method) => {
Route.prototype[method] = function (handler) {
let layer = new Layer("里层的用户的逻辑不需要这个path", handler)
layer.method = method
this.methods[method] = true // {get:true}
this.stack.push(layer)
}
})
Route.prototype.dispatch = function (req, res, out) {
let idx = 0
const next = (err) => {
console.log("run")
if (err) return out(err)
if (idx === this.stack.length) return out()
let layer = this.stack[idx++]
if (req.method.toLowerCase() === layer.method) {
// 用户绑定的方法
layer.handle_request(req, res, next)
} else {
next()
}
}
next()
}
export default Route