const matchedResults = pathname.match(route.pattern); if (route.method === method && matchedResults) { addParamsToRequest(req, route.path, matchedResults); route.handler(req, res, next); } else { next(); }
const addParamsToRequest = (req, routePath, matchedResults) => { req.params = {}; let urlParameterNames = routePath.match(/:(\w+)/g); if (urlParameterNames) { for (let i=0; i < urlParameterNames.length; i++) { req.params[urlParameterNames[i].slice(1)] = matchedResults[i + 1]; } } }
添加个 route 测试一下:
router.get('/actors/:year/:country', (req, res) => { res.end(`year: ${req.params.year} country: ${req.params.country}`); });
访问:9527/actors/1990/China试试:
router 模块就写到此,至于查询参数的格式化以及获取请求主体,比较琐碎就不试验了,需要可以直接使用bordy-parser等模块。
现在我们已经创建好了router模块,接下来将 route handler 内的业务逻辑都转移到 controller 中去。
修改__server.js__,引入 controller:
... const actorsController = require('./controllers/actors'); ... router.get('/actors', (req, res) => { actorsController.getList(req, res); }); router.get('/actors/:name', (req, res) => { actorsController.getActorByName(req, res); }); router.get('/actors/:year/:country', (req, res) => { actorsController.getActorsByYearAndCountry(req, res); }); ...
新建__controllers/actors.js__:
const actorsTemplate = require('../views/actors-list'); const actorsModel = require('../models/actors'); exports.getList = (req, res) => { const data = actorsModel.getList(); const htmlStr = actorsTemplate.build(data); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(htmlStr); }; exports.getActorByName = (req, res) => { const data = actorsModel.getActorByName(req.params.name); const htmlStr = actorsTemplate.build(data); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(htmlStr); }; exports.getActorsByYearAndCountry = (req, res) => { const data = actorsModel.getActorsByYearAndCountry(req.params.year, req.params.country); const htmlStr = actorsTemplate.build(data); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(htmlStr); };
在 controller 中同时引入了 view 和 model, 其充当了这二者间的粘合剂。回顾下 controller 的任务:
controller 收到请求,向 model 索要数据
model 给 controller 返回其所需数据
controller 可能需要对收到的数据做一些再加工
controller 将处理好的数据交给 view
在此 controller 中,我们将调用 model 模块的方法获取演员列表,接着将数据交给 view,交由 view 生成呈现出演员列表页的 html 字符串。最后将此字符串返回给客户端,在浏览器中呈现列表。
从 model 中获取数据
通常 model 是需要跟数据库交互来获取数据的,这里我们就简化一下,将数据存放在一个 json 文件中。
/models/test-data.json
[ { "name": "Leonardo DiCaprio", "birth year": 1974, "country": "US", "movies": ["Titanic", "The Revenant", "Inception"] }, { "name": "Brad Pitt", "birth year": 1963, "country": "US", "movies": ["Fight Club", "Inglourious Basterd", "Mr. & Mrs. Smith"] }, { "name": "Johnny Depp", "birth year": 1963, "country": "US", "movies": ["Edward Scissorhands", "Black Mass", "The Lone Ranger"] } ]
接着就可以在 model 中定义一些方法来访问这些数据。
models/actors.js
const actors = require('./test-data'); exports.getList = () => actors; exports.getActorByName = (name) => actors.filter(actor => { return actor.name == name; }); exports.getActorsByYearAndCountry = (year, country) => actors.filter(actor => { return actor["birth year"] == year && actor.country == country; });
当 controller 从 model 中取得想要的数据后,下一步就轮到 view 发光发热了。view 层通常都会用到模板引擎,如 dust 等。同样为了简化,这里采用简单替换模板中占位符的方式获取 html,渲染得非常有限,粗略理解过程即可。
创建 /views/actors-list.js: