koa不愧为小而美,主要代码很少。
简单来说,
1,koa封装了node的http.createServer((req,res)=>{})的
入参req,res到ctx(一个自定义对象)的req,res属性中,
并且额外提供了ctx.request,ctx.request提供一些快捷的操作。
const app = Koa() app.use(middlewareFn)
2.方法use函数接收参数fn,放入中间件middleware[]数组里面。
handleRequest(ctx, fnMiddleware) { const res = ctx.res; const handleResponse = () => respond(ctx); return fnMiddleware(ctx).then(handleResponse).catch(onerror); }
fnMiddleware即处理过的middleware数组:
function compose (middleware) { return function (context, next) { // last called middleware # let index = -1 return dispatch(0) function dispatch (i) { if (i <= index) return Promise.reject(new Error('next() called multiple times')) index = i let fn = middleware[i] if (i === middleware.length) fn = next if (!fn) return Promise.resolve() try { return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); } catch (err) { return Promise.reject(err) } } } }
递归的展开就是洋葱模型了:
const [fn1, fn2, fn3] = this.middleware; const fnMiddleware = function(ctx){ return Promise.resolve( fn1(context, function next(){ return Promise.resolve( fn2(context, function next(){ return Promise.resolve( fn3(context, function next(){ return Promise.resolve(); }) ) }) ) }) ); }; fnMiddleware(ctx).then(handleResponse).catch(onerror);
ctx:
createContext(req, res) { const context = Object.create(this.context); const request = context.request = Object.create(this.request); const response = context.response = Object.create(this.response); context.app = request.app = response.app = this; context.req = request.req = response.req = req; context.res = request.res = response.res = res; request.ctx = response.ctx = context; request.response = response; response.request = request; context.originalUrl = request.originalUrl = req.url; context.state = {}; return context; }