在express构建的程序中,配置一个路由规则可以用 app.get(urlPath, callback)
方式,也可以用路由中间件 app.use(urlPath, express.Router)
,但是在项目扩大时候这种配置会显得很冗余,所以就需要实现一种路由自动加载的机制。
1.项目目录与路由规则映射
自动加载路由的原理就是找出控制器的目录结构和路由规则的匹配关系,比如请求/
就是对应控制器的根目录,那么请求/home/api
就是对应下面的目录结构:
而请求的url路径的最后一个块可以当成是这个控制器的一个导出的方法,比如/home/api/getlunbo
对应如下:
注意的是index
可以省略,也就是说访问/home/api/
就是相当于访问 index
方法
2.构建控制器对象的配置
如果我们只是单纯的把控制器对象导出的方法都搞成一个function
,那么对于类似 /member/list/:id
这种路由规则就无法绑定。所以我们可以考虑导出一个object
,在这个对象配置一个属性。比如:params
表示所有占位参数数据,method
表示请求的方法,handler
表示对应的处理函数,如下:
3.自动加载函数
自动加载函数用到glob
模块来同步读取控制器下面的文件,根据目录结构和配置对象参数来构造出路由中的路径,绑定对应的handler
。
const glob = require('glob');
function autoLoad(app, root) {
// 同步读取root目录下的所有js文件
glob.sync(`${root}/**/*.js`).forEach((file) => {
// 利用控制器目录结构构和方法构建路由url
let filePath = file.replace(/\.[^.]*$/, '');
let controller = require(file);
let urlPath = filePath.replace(root, '').replace(/\/index$/, '');
let methods = Object.keys(controller);
function applyMethod(name, methodBody) {
let body = methodBody;
let routeURL = urlPath + (name === 'index' ? '' : `/${name}`);
let method = 'get';
let handler;
let params;
switch(typeof body) {
case 'function':
handler = body;
break;
case 'object':
params = body.params || [];
method = (body.method || 'get').toLowerCase();
routeURL = routeURL + '/' + params.join('/');
handler = body.handler;
break;
default: return;
}
// 绑定路由规则
app[method](routeURL, handler);
// 这里兼容访问index的情况
if(name === 'index') {
app[method](routeURL + '/index', handler);
}
}
methods.forEach(function(method){
let methodName = method;
let methodBody = controller[method];
applyMethod(methodName, methodBody);
});
});
}
module.exports = autoLoad;
在入口处导入并调用:
const express = require('express')
const path = require('path')
const autoLoadRouter = require('./routes/autoLoad')
let app = express()
autoLoadRouter(app, path.join(__dirname, 'controller'))
4.配置参数扩展
- 考虑到某些控制器不需要配置路由规则,我们可以增加一个排除的控制器路径数组。
- 另外某些路由需要中间件处理,我们可以增加一个中间件函数数组,在函数里面调用
next()
依次执行中间件,最后才调用我们的handler
- 增加一个重写url规则的配置,绑定重写后的url规则即可