设为首页 加入收藏

TOP

使用Node.js实现简易MVC框架(二)
2017-10-10 16:01:19 】 浏览:9938
Tags:使用 Node.js 实现 简易 MVC 框架
ter = (req, res) => { }; router.use = (fn) => { routes.push({ method: null, path: null, handler: fn }); }; METHODS.forEach(item => { const method = item.toLowerCase(); router[method] = (path, fn) => { routes.push({ method, path, handler: fn }); }; }); };

以上主要是给 router 添加了 usegetpost 等方法,每当调用这些方法时,给 routes 添加一条 route 规则。

Note:

java script 中函数是一种特殊的对象,能被调用的同时,还可以拥有属性、方法。

接下来的重点在 router 函数,它需要做的是:

  1. req对象中取得 method、pathname
  2. 依据 method、pathname 将请求与routes数组内各个 route 按它们被添加的顺序依次匹配
  3. 如果与某个route匹配成功,执行 route.handler,执行完后与下一个 route 匹配或结束流程 (后面详述)
  4. 如果匹配不成功,继续与下一个 route 匹配,重复3、4步骤
    const router = (req, res) => {
        const pathname = decodeURI(url.parse(req.url).pathname);
        const method = req.method.toLowerCase();
        let i = 0;

        const next = () => {
            route = routes[i++];
            if (!route) return;
            const routeForAllRequest = !route.method && !route.path;
            if (routeForAllRequest || (route.method === method && pathname === route.path)) {
                route.handler(req, res, next);
            } else {
                next();
            }
        }

        next();
    };

对于非路由中间件,直接调用其 handler。对于路由中间件,只有请求方法和路径都匹配成功时,才调用其 handler。当没有匹配上的 route 时,直接与下一个route继续匹配。

需要注意的是,在某条 route 匹配成功的情况下,执行完其 handler 之后,还会不会再接着与下个 route 匹配,就要看开发者在其 handler 内有没有主动调用 next() 交出控制权了。

在__server.js__中添加一些route:

router.use((req, res, next) => {
    console.info('New request arrived');
    next()
});

router.get('/actors', (req, res) => {
    res.end('Leonardo DiCaprio, Brad Pitt, Johnny Depp');
});

router.get('/actresses', (req, res) => {
    res.end('Jennifer Aniston, Scarlett Johansson, Kate Winslet');
});

router.use((req, res, next) => {
    res.statusCode = 404;
    res.end();
});

每个请求抵达时,首先打印出一条 log,接着匹配其他route。当匹配上 actors 或 actresses 的 get 请求时,直接发回演员名字,并不需要继续匹配其他 route。如果都没匹配上,返回 404。

在浏览器中依次访问 http://localhost:9527/erwehttp://localhost:9527/actorshttp://localhost:9527/actresses 测试一下:

404

network 中观察到的结果符合预期,同时后台命令行中也打印出了三条 New request arrived语句。

接下来继续改进 router 模块。

首先添加一个 router.all 方法,调用它即意味着为所有请求方法都添加了一条 route:

    router.all = (path, fn) => {
        METHODS.forEach(item => {
            const method = item.toLowerCase();
            router[method](path, fn);
        })
    };

接着,添加错误处理。

/lib/router.js

const defaultErrorHander = (err, req, res) => {
    res.statusCode = 500;
    res.end();
};

module.exports = (errorHander) => {
    const routes = [];

    const router = (req, res) => {
            ...
        errorHander = errorHander || defaultErrorHander;

        const next = (err) => {
            if (err) return errorHander(err, req, res);
            ...
        }

        next();
    };

server.js

...
const router = require('./lib/router')((err, req, res) => {
    console.error(err);
    res.statusCode = 500;
    res.end(err.stack);
});
...

默认情况下,遇到错误时会返回 500,但开发者使用 router 模块时可以传入自己的错误处理函数将其替代。

修改一下代码,测试是否能正确执行错误处理:

router.use((req, res, next) => {
    console.info('New request arrived');
    next(new Error('an error'));
});

这样任何请求都应该返回 500:

error stack

继续,修改 route.path 与 pathname 的匹配规则。现在我们认为只有当两字符串相等时才让匹配通过,这没有考虑到 url 中包含路径参数的情况,比如:

localhost:9527/actors/Leonardo

router.get('/actors/:name', someRouteHandler);

这条route应该匹配成功才是。

新增一个函数用来将字符串类型的 route.path 转换成正则对象,并存入 route.pattern:

const getRoutePattern = pathname => {
  pathname = '^' + pathname.replace(/(\:\w+)/g, '\(\[a-zA-Z0-9-\]\+\\s\)') + '$';
  return new RegExp(pathname);
};

这样就可以匹配上带有路径参数的url了,并将这些路径参数存入 req.params 对象:

        const matchedResults = pathname.match
首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇JavaScript--数组 下一篇jQuery对象和DOM对象和字符串之间..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目