逐行解析Express核心原理
文章主要以一下三个部分组成
- node 创建http服务
- express 创建http服务
- 自己写类express并且解析核心原理
1. node创建http 服务
基于node基本的创建服务
//引入node 模块
const http = require('http')
//创建服务,并且实现callback回调
const server = http.createServer(callback)
const callback = (req,res) =>{
res.end("Hello xie")
}
//服务监听3000 端口
server.listen(3000)
上面我们用最原始的方式 创建一个服务,当访问localhost:3000即可返回相关数据
2. 使用express 创建服务
npm install express --save
const express = require('express')
const app = express()
const port = 3000
//路由
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
使用express的优势在于其可以使用中间件,这也是其核心,所谓的中间件,其实也即使一个函数function
/**
定义一个中间件,
暂且忽略next是啥,知道next是一个往下传递的方法即可
*/
const middle = (req,res,next) =>{
//do something
next()
}
app.use(middle)
app.use("/api",middle, (req,res,next)=>{
//dosomething
next()
})
app.get(参数类似use参数)
app.post(参数类似use参数){
res.json({
name:'xieyusheng'
})
}
......
那么问题来了,app.use/get/post/res.json以及最至关重要的next是怎么实现的呢?
3.自己写个Express框架
姑且就叫XExpress
1. 先定义接结构
const http = require('http')
class XExpress{
use () {
}
get () {
}
post () {
}
callback (){
}
listen(...argus){
const server = http.createServer(callback)
server.listen(...argus)
}
}
module.exports = () => new Exprerss()
实例化
const xErpress = './xExpress'
const server = new xErpress()
server.listen(3000)
ok,基本服务启动好了,那么use/get等怎么处理呢,这里核心原理来了哦,其实我们只要将所有的中间件函数放在一个栈中,然后一个一个执行处理,那么怎么一个个处理呢? 使用next函数
2. 将所有的中间件放在堆栈中
//new XExpress 实例化一个单量
constructor(){
//存放中间件的list
this.routes = {
use: [], // app.use(...)
get: [], // app.get(...)
post: [] // app.post(...)
}
}
//结构化传递来的参数
register (path) {
const info = {};
if(typeof path == "string"){
info.path = path;
//将后面的方法以arr的方式,放入内存中,从第二个参数开始
info.stack = slice.call(arguments, 1)
}else{
info.path = "/" //当use等方法的第一个参数是否是链接
//从第一个参数开始,转换为数组,存入 stack
info.stack = slice.call(arguments, 1)
}
return info;
// info={
// path:'/',
// stack:[
// ()=>{};
// ()=>{}
// ]
// }
}
use(){
const info = this.register.apply(this, arguments)
this.routes.all.push(info)
}
....get/post类似
所有的中间件都赋予在routes里面,那么当请求来了,我们匹配下,然后一个个的执行
callback(req,res) => {
//定义方法给req
req.json= () =>{
// 定义返回格式
res.setHeader("Contype-type" : "application/json")
res.end(
JSON.stringify(data)
)
}
//1.匹配相对的中间件
const url = req.url
const method = req.method.toLowerCase()
//匹配
const resultList = this.match(method, url)
//一个一个的执行中间件函数
this.actionNext(req, res, resultList)
}
/**
根据url和method匹配相对应的中间件LIST
*/
match(method, url) {
let stack = []
// 获取 routes
let curRoutes = []
curRoutes =[...this.routes.use]
curRoutes = [...this.routes.use[method]]
curRoutes.forEach(routeInfo => {
if (url.indexOf(routeInfo.path) === 0) {
stack = stack.concat(routeInfo.stack)
}
})
return stack
}
actionNext(req, res, stack){
// 定义next函数
const next = () =>{
const middleware = stack.shift() //取出第一个
if(middleware) {
//将next 函数传递
middleware(req,res,next)
}
}
next();
}
这样,next函数传递给每个中间函数了,这里的next函数就是下一个要执行函数的包装体