这是我参与更文挑战的第 28 天,活动详情查看:更文挑战
koa-route
是 koa
的一个路由中间件。
在不使用该中间件的情况下,我们实现路由的方式如下所示:
const Koa = require('koa');
const app = new Koa();
// switch-case 实现
const route = ctx => {
switch (ctx.path) {
case '/name':
ctx.body = 'LvLin';
return;
case '/age':
ctx.body = '25';
return;
default:
return;
}
};
app.use(route);
app.listen(3000);
复制代码
通过koa-route
,我们实现路由代码如下:
const Koa = require('koa');
const route = require('koa-route');
const app = new Koa();
const name = ctx => {
ctx.body = 'LvLin';
}
const age = ctx => {
ctx.body = '25';
}
app.use(route.get('/name', name));
app.use(route.get('/age', age));
app.listen(3000);
复制代码
复杂一些的例子如下:
const _ = require('koa-route');
const Koa = require('koa');
const app = new Koa();
const db = {
tobi: { name: 'tobi', species: 'ferret' },
loki: { name: 'loki', species: 'ferret' },
jane: { name: 'jane', species: 'ferret' }
};
const pets = {
list: (ctx) => {
const names = Object.keys(db);
ctx.body = 'pets: ' + names.join(', ');
},
show: (ctx, name) => {
const pet = db[name];
if (!pet) return ctx.throw('cannot find that pet', 404);
ctx.body = pet.name + ' is a ' + pet.species;
}
};
app.use(_.get('/pets', pets.list));
app.use(_.get('/pets/:name', pets.show));
app.listen(3000);
console.log('listening on port 3000');
复制代码
源码分析
看一下外部依赖:
const pathToRegexp = require('path-to-regexp');
const debug = require('debug')('koa-route');
const methods = require('methods');
复制代码
methods
源码很简单,以数组形式导出了 Node 支持的所有 HTTP 方法。
path-to-regexp
用于将路由 path
转换成正则表达式,通过该正则能够匹配符合的请求path
。
koa-route
源码分析如下:
// 对 methods 进行遍历,初始化
methods.forEach(function(method){
module.exports[method] = create(method);
});
module.exports.del = module.exports.delete;
module.exports.all = create();
function create(method) {
if (method) method = method.toUpperCase();
return function(path, fn, opts){
// 返回路径的匹配正则
const re = pathToRegexp(path, opts);
debug('%s %s -> %s', method || 'ALL', path, re);
const createRoute = function(routeFunc){
return function (ctx, next){
// 判断请求的 method 是否匹配
if (!matches(ctx, method)) return next();
// 判断 path 是否匹配
const m = re.exec(ctx.path);
if (m) {
// 获取 path 携带的参数,并进行 url 解码
const args = m.slice(1).map(decode);
ctx.routePath = path;
debug('%s %s matches %s %j', ctx.method, path, ctx.path, args);
// ctx 作为路由中间件第一个参数
args.unshift(ctx);
// next 方法作为路由中间件最后一个参数
args.push(next);
return Promise.resolve(routeFunc.apply(ctx, args));
}
// 路径不匹配,进入下一个
return next();
}
};
if (fn) {
return createRoute(fn);
} else {
return createRoute;
}
}
}
// url 解码
function decode(val) {
if (val) return decodeURIComponent(val);
}
// 检查请求 method 是否一致
function matches(ctx, method) {
if (!method) return true;
if (ctx.method === method) return true;
if (method === 'GET' && ctx.method === 'HEAD') return true;
return false;
}
复制代码
相关资料
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END