前言
最近需要做Node
中间层的需求,优雅的名字是back-end for front-end(BEF)
,实现前后端彻底解耦。BFE
由来已久,服务端服务前端的一种逻辑分层模式,这种分层模式由来已久。在做中间层API
接口开发时,选用Koa
作为创建Node
服务的JavaScript
库,因此在各种文档中经常见到路由挂载的代码。
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
router
.get('/', async (ctx, next) => {
// do something
})
.post('/login', async (ctx, next) => {
// do something
});
app
.use(router.routes())
.use(router.allowedMethods());
app.listen(3000, () => {
console.log('server is runnung: http://localhost:3000');
});
在进行路由挂载的时候一直很好奇:
new Router()
到底做了什么呢?router
如何实现具体路径匹配到置顶函数的?router.routes()
到底做了什么呢?router.allowedMethods()
到底做了什么呢?- 能不能不要写这样的
.get/.put
的样板代码进行路由挂载,而通过一个router-config.js
文件生成server
端路由呢?
基础
再搞懂这些问题首先我们需要明确亮点:1、没有Koa
使用node
的http
模块如何使用路由;2、Koa
是中间件机制的(时刻记住,Koa
实现各种功能就是执行对应的moddleware
)。
// 使用 http 模块实现路由
const http = require('http');
const {
parse } = require('url');
function callback(req, res) {
// 根据req.url执行对应的action
const {
pathname } = parse(req.url);
switch (pathname) {
case '/':
// do something
break;
...
default:
break;
}
};
const server = http.createServer(callback);
// 使用事件监听执行callback
server.on('request', callback);
server.listen(3000);
// 使用 koa-router 实现路由
const Koa = require('koa');
const KoaRouter = require('koa-router');
const app = new Koa();
// 创建 router 实例对象
const router = new KoaRouter();
//注册路由
router.get('/', async (ctx, next) => {
ctx.body = {
code: 200,
msg: 'success',
data: 'index'
};
});
app.use(router.routes()); // 添加路由中间件
app.use(router.allowedMethods()); // 对请求进行一些限制处理
app.listen(3000);
而且我们知道Koa
实际上就是将中间件应用在callback
中,每次request
进来时执行一次所有的中间件函数,从而响应对应的请求。也就是说,其实koa-router
也是在对应的路由匹配到之后,执行相应的中间件函数,从而响应对应的请求的。因此我们可以大胆的猜测一下,.get/.put
等方法是实现路由和操作函数的绑定,router.routes()
是将路由中间件进行注册到Koa
的middleware
数组中等待执行,router.allowedMethods()
是执行一些异常兜底操作的。
源码架构
koa-router
的源码很简单主要是lib
目录下的两个文件layer.js
和router.js
。
首先我们看一下入口文件router.js
文件做了什么。
// 依赖文件导入
var debug = require('debug')('koa-router');
var compose = require('koa-compose');
var HttpError = require('http-errors');
var methods = require('methods');
var Layer = require('./layer')</