简单实现一个Express类

话不多说,直接贴代码。

  • express.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
const http = require('http');
const slice = Array.prototype.slice;

class Express {
constructor () {
this._index = 0;
this.routes = {
all: [],
get: [],
post: []
}
}

use () {
const info = this._init.apply(this, arguments);
this.routes.all.push(info)
}
get () {
const info = this._init.apply(this, arguments);
this.routes.get.push(info)
}
post () {
const info = this._init.apply(this, arguments);
this.routes.post.push(info)
}
listen () {
const server = http.createServer(this._callback());
server.listen(...arguments);
}
_init (path) {
const info = {};
if (typeof path === 'string') {
info.path = path;
info.stack = slice.call(arguments, 1);
} else {
info.path = '/';
info.stack = slice.call(arguments, 0)
}
info.index = this._index++;
return info;
}
_callback () {
return (req, res) => {
res.json = (data) => {
res.setHeader('Content-type', 'application/json');
res.end(JSON.stringify(data));
}
const { url, method } = req;
const stacks = this._matchRoute(url, method.toLowerCase());
this._handle(req, res, stacks);
}
}
_handle (req, res, stacks) {
let index = 0;
const next = () => {
stacks[index] && stacks[index++](req, res, next);
}
next(req, res, next)
}
_matchRoute (url, method) {
if (url === '/favicon.ico') {
return [];
}

const mergedRoutes = this.routes.all.concat(this.routes[method]);

const sortedStacks = new Array(mergedRoutes.length);
mergedRoutes.forEach(val => {
sortedStacks[val.index] = val;
})

return sortedStacks.reduce((prev, next) => {
if (url.indexOf(next.path) === 0) {
prev = [...prev, ...next.stack];
}
return prev;
}, [])
}
}

module.exports = () => {
return new Express()
}
  • test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const express = require('./express')
// const express = require('./express-like')

// 本次 http 请求的实例
const app = express()

app.use((req, res, next) => {
console.log('use请求开始...', req.method, req.url)
next()
})

app.use('/api', (req, res, next) => {
console.log('use 处理 /api 路由')
next()
})

app.get('/api', (req, res, next) => {
console.log('get /api 路由')
next()
})

app.use((req, res, next) => {
// 假设在处理 cookie
console.log('use 处理 cookie ...')
req.cookie = {
userId: 'abc123'
}
next()
})

app.listen(8000, () => {
console.log('server is running on port 8000')
})