express
- req.cookies cookie-parser 处理cookie挂载
- req.query, req.body拦截请求参数
- express.json() 转化json (解析json格式的请求参数,赋值到req.body,返回参数json格式)
- express.urlencoded() 解析req 其他格式的数据
- express-session connect-redis
- morgan 输出日志 通过文件流写入日志(flags: 'a') ,配置参数:https://github.com/expressjs/morgan
- router=express.Router()
- app.use(命中, 回调中间件)
中间件
- 中间件用于帮助我们做一些繁琐的基本工作,如路由匹配(koa-router),参数提取(koa-bodypaser),响应json数据(koa-json),支持跨域(koa-cors),保持用户登录状态(koa-session/koa-jwt)
- 中间件的设计,专注于解决一个问题,通过中间件的组合来实现功能的拓展
- 中间件运行,尾调用的洋葱模型
express和koa的区别
- koa不在内核中绑定任何中间件,express则内置了一些功能如express.Router()
- koa原生支持async await 相比于promise处理异步回调更加优雅
- 最重要的是两者对异步的中间件调用顺序是不同的,express不会等待中间件的异步处理执行完毕,主要是由于内部是通过回调函数的组合,其next的机制导致不会等待异步的完成而继续执行同步操作,当然对于一个中间件的内部使用了async await,执行顺序还是正确的;
而koa它的next机制是利用闭包和递归的性质,一个个执行中间件,并且每次执行都是返回promise的封装,再结合generator状态机,实现同步异步的按顺序执行
中间件的实现
- express
脚手架:express
1、分解来看 有use get post方法可以注册路由 listen进行监听
2、注册路由时需要对参数进行匹配,分解为path和对应的中间件列表作为对象存储
3、listen监听注册回调函数处理中间件
4、中间件的收集需要匹配方法和路径
6、中间件的触发,需要调用next函数进行依次触发
7、repress-session; require('connect-redis')(session)
- koa
koa1 用generator实现
koa2 async await实现 结合node8+支持 实现更加完美
脚手架 npm i koa-generator; koa2初始化
1、koa-router; router.prefix(/)
2、中间件必须以async开头,保证next执行顺序,通过await等待异步的执行
3、ctx封装了request和response
3、返回值可以直接赋值给ctx.body 不需要处理json格式和异步回调promise返回
4、koa-generic-session koa-redis
5、实现koa无需考虑路径匹配,主要在于回调函数的处理,需要对中间件进行promise的包装,保证执行顺序
6、ctx的参数包装
// 简单实现express
const http = require("http");
const slice = Array.prototype.slice;
class LikeExpress {
constructor() {
this.routes = {
all: [],
get: [],
post: []
};
}
register() {
let info = {};
if (typeof arguments[0] === "string") {
info.path = arguments[0];
info.stack = slice.call(arguments, 1);
} else {
info.path = "/";
info.stack = slice.call(arguments, 0);
}
return info;
}
use() {
let result = this.register.apply(this, arguments);
this.routes.all.push(result);
console.log('all', this.routes.all)
}
get() {
let result = this.register.apply(this, arguments);
this.routes.get.push(result);
}
post() {
let result = this.register.apply(this, arguments);
this.routes.post.push(result);
}
match(method, url) {
let resultList = [];
let stack = [];
stack = stack.concat(this.routes.all);
stack = stack.concat(this.routes[method]);
if (url === "favicon.icon") {
return resultList;
}
for (let item of stack) {
if (item.path.indexOf(url) === 0) {
resultList = resultList.concat(item.stack);
}
}
console.log('resut', resultList)
return resultList;
}
handler(req, res, list) {
const next = () => {
let middleware = list.shift();
if (typeof middleware === 'function') {
middleware(req, res, next);
}
};
next();
}
callback() {
return (req, res) => {
res.json = (data) => {
res.setHeader("Content-type", "application/json");
res.end(JSON.stringify(data));
};
let url = req.url;
let method = req.method.toLowerCase();
let resultList = this.match(method, url);
console.log('list', resultList)
this.handler(req, res, resultList);
};
}
listen(...args) {
let server = http.createServer(this.callback());
server.listen(...args);
}
}
module.exports = () => {
return new LikeExpress();
};
// 简单koa2实现 主要是promise对象的包装
const http = require("http");
// 组合中间件
function compose(middlewareList) {
return function(ctx) {
function dispath(i) {
const fn = middlewareList[i]
try {
return Promise.resolve(
fn(ctx, dispath.bind(null, i+1))
)
} catch (err) {
return Promise.reject(err)
}
}
return dispath(0)
}
}
class LikeKoa2 {
constructor() {
this.middlewareList = [];
}
use(fn) {
this.middlewareList.push(fn);
return this;
}
createContent(req, res) {
const ctx = {
req, res
}
ctx.query = req.query
return ctx
}
handler(ctx, fn) {
return fn(ctx)
}
callback() {
const fn = compose(this.middlewareList)
return (req, res, next)=> {
const ctx = this.createContent(req, res)
return this.handler(ctx, fn)
}
}
listen(...args) {
let server = http.createServer(this.callback());
server.listen(...args);
}
}
module.exports = () =>{
return new LikeKoa2()
}
网友评论