返回
Koa 源码剖析,深入了解 Koa 原理
前端
2024-02-10 10:18:14
Koa 源码剖析
首先要说明的是,本文分析的 Koa 源码版本是 Koa 的第一个发布版本(0.0.2)。该版本的文件结构非常简单,只有三个文件:application.js、context.js 和 status.js。接下来,我们将依次分析这三个文件。
Context
Context 是 Koa 中最重要的部分之一,也是代码量最多的部分。
// context.js
var util = require('util');
var Stream = require('stream');
var Response = require('./response');
function Context() {
this.state = {};
this.res = new Response();
}
util.inherits(Context, Stream);
Context.prototype.inspect = function() {
return util.format('%s %s (%d %s)', this.method, this.originalUrl, this.res.statusCode, http.STATUS_CODES[this.res.statusCode]);
};
exports = module.exports = Context;
Context 是一个继承自 Stream
类的对象,它包含了请求和响应相关的属性和方法。
this.state
:一个存储状态信息的对象,可以被中间件和控制器使用。this.res
:一个Response
对象,用于发送响应。this.method
:请求方法,如GET
或POST
。this.originalUrl
:原始请求 URL,包括查询参数。this.res.statusCode
:响应状态码,如200
或404
。
Application
Application 是 Koa 的主类,它负责处理请求并将其路由到相应的中间件和控制器。
// application.js
var http = require('http');
var EventEmitter = require('events').EventEmitter;
var slice = Array.prototype.slice;
var parse = require('url').parse;
var Context = require('./context');
var Response = require('./response');
function Application() {
this.middleware = [];
}
util.inherits(Application, EventEmitter);
Application.prototype.listen = function() {
var server = http.createServer(this.callback());
return server.listen.apply(server, arguments);
};
Application.prototype.callback = function() {
var fn = this.handle.bind(this);
return function(req, res) {
var ctx = createCtx(req, res);
fn(ctx).then(function() {
res.end();
}).catch(function(err) {
ctx.app.emit('error', err, ctx);
res.end();
});
};
};
Application.prototype.use = function(fn) {
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
this.middleware.push(fn);
return this;
};
Application.prototype.handle = function(ctx, next) {
var idx = -1;
var stack = this.middleware;
var next = function() {
var layer = stack[++idx];
if (!layer) {
// delegate to the final handler (which is the app itself)
return this.respond(ctx);
}
try {
// convert to Promise
var onerror = handleError(ctx, next);
var res = Promise.resolve(layer(ctx, onerror));
// capture rejection for Koa's downstream error handling middleware
// or any other rejections that happen downstream
if (res && typeof res.catch === 'function') {
return res.catch(onerror);
}
} catch (err) {
// if an error happens in a synchronous middleware,
// pass it to the downstream error middleware
return onerror(err);
}
};
// invoke stack of middlewares
next();
};
Application.prototype.respond = function(ctx) {
// allow bypassing middleware
if (ctx.res._explicitStatus) {
ctx.res.end();
return;
}
// attempt to match request path
var path = parse(ctx.req.url).pathname;
var layer = match(this.router, path);
if (layer) {
var fn = layer.handler;
var arity = fn.length;
var onerror = handleError(ctx, ctx.onerror);
if (arity < 4) {
return fn(ctx, onerror);
} else {
// request, response, next(err)
return fn(ctx.req, ctx.res, onerror);
}
}
};
exports = module.exports = Application;
Application 对象主要包含以下方法:
this.listen()
:监听指定端口并启动服务器。this.callback()
:返回一个 Koa 中间件函数,该函数用于处理请求。this.use()
:添加中间件。this.handle()
:处理请求。this.respond()
:响应请求。
Status
Status 对象包含了一系列 HTTP 状态码,方便在应用程序中使用。
// status.js
module.exports = {
200: 'OK',
201: 'Created',
202: 'Accepted',
204: 'No Content',
301: 'Moved Permanently',
302: 'Found',
304: 'Not Modified',
400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
500: 'Internal Server Error'
};
总结
通过对 Koa 源码的分析,我们了解了 Koa 的基本原理和实现机制。这有助于我们更好地理解和使用 Koa,并开发出更加强大的 Node.js 应用。