这是渐进式Express源码学习 | 小白也能懂源码系列文章的第一篇。
请结合该节代码阅读Lesson1-万物归宗
预期特性和预期用法
这篇文章我们实现一个最最基础的Web框架,功能包括
- 默认响应客户端请求
- 当请求到来时,返回给用户一个字符串
具体的用法如下(我们用my-express表示这个框架)
const express = require('../index.js')
const app = express()
app.listen(3000)
复制代码
源码及讲解
首先在Node中,和网络请求相关的模块是http,我们可以用http搭建一个简单的web服务器,如下代码
const http = require('http')
const server = http.createServer(function (req,res) {
res.end('Response From Server')
})
server.listen(3000)
复制代码
上面的代码中,我们调用http模块的createServer函数,传入一个相应请求的函数。这个就是一个简单的Web服务,非常好理解。Node文档里对createServer函数有说明。
基于上面的代码,我们稍微做下调整,就是我们第一个Express的源码,如下
const http = require('http')
const mixin = require('merge-descriptors')
module.exports = function createServer() {
const app = function (req, res) {
res.end('Response From Server')
}
mixin(app, proto, false)
return app
}
const proto = Object.create(null)
proto.listen = function (port) {
const server = http.createServer(this)
return server.listen.apply(server, arguments)
}
复制代码
代码开头,我们引入http模块和merge-descriptors模块。http模块是Node原生模块不多说,merge-descriptors是第三方模块,主要是通过descrptors合并对象,他的用法是
var thing = {
get name() {
return 'jon'
}
}
var animal = {
}
merge(animal, thing)
animal.name === 'jon'
复制代码
更多关于merge-descriptors的实现可以看https://github.com/component/merge-descriptors
然后我们exports是一个函数,用户调用之后,会拿到一个对象,这个对象本身是一个函数,并且还有一个listen方法。当调用app.listen的时候,实际上就调用了http模块的createServer函数,然后把自己当做requestListener传入
动手实验
目前我们整个项目的文件结构是
我们首先通过命令node example/index.js运行样例 然后我们通过下面命令来测试我们的程序是否正常工作
curl http://localhost:3000
复制代码
结果如图
所以我们的程序是正常工作了,我们第一个版本的Express也实现好了。现实的Express还有很多其他功能,我们一步一步添加。
本文总结
本文实现了一个最基础的Express,他能默认响应客户端的请求。本质上他是从http模块衍生来的,同样的,express也是从http衍生过来的。