這次帶給大家Nodejs路由與控制器的使用,Nodejs路由與控制器使用的注意事項有哪些,下面就是實戰案例,一起來看一下。
因為工作需要,最近再次學習了node,上一次學習node是2014年,純粹是個人興趣,學了入門之後沒有運用,加上趕別的項目又不了了之。這次正好撿起來。廢話不多說,這裡的MEAN指的是Mongodb、Express、Angular和Node。 透過整個專案逐步整合在一起。 MEAN堆疊最大的特色不是運用了哪些框架或第三方,而是前後端都是一種語言,即JavaScript。早年我也是對node抱著疑態度,覺得這個頁面上操作dom的腳本語言,能扛得起後端那麼多模組嗎?但懷疑不防多了解一下,才決定寫這個系列的文章。
Mongodb做資料存儲,Express是基於node的後端框架,Angular是前端框架,Node是後端運行環境。安裝過程和node的特性就不講了,網路上一大把。開發環境是VS2013.安裝了NTVS。 node安裝完後,有時候需要設定下環境變數。在cmd目錄下輸入 node -v 如果顯示版本號,則表示安裝正確了。
起始工程
在VS中新項目,選擇JavaScript-->Node.js,選擇Express4的應用程式。
為了避免一直Ctrl+C,安裝nodemon,檔案更新,它會自動重啟,-g表示安裝成全域。
npm install nodemon -g
修改routes資料夾下的index.js中的title為ReadingClub。然後用cmd切到工程目錄,輸入nodemon啟動工程。
在瀏覽器裡面存取lochost:3000 ,成功開啟:
先看routes資料夾下面的index .js ,這就是一個簡單的路由,處理的路徑為「/」,請求方式get,req代表的是request,res代表的response。
render方法有兩個參數,“index”,代表的是要渲染的視圖模板名稱,這裡預設的視圖引擎是jade,而後面{title:' ReadingClub'}就是傳遞到視圖的資料模型。這裡和Asp.net MVC 的return View() 有些相似,而這裡的function就相當 Asp.net MVC中Controller的一個Action。 View()預設是對應目前Action名稱的視圖。而render必須指定。
res 也可以直接發回一個回應
res.send('respond with a resource');
建立Controllers
# 不像Asp.net MVC有預設的路由規則,Express的路由需要一個個配置,不妨把Controller提出來。但在此之前,我們先修改一下目錄。如下,建立app_server資料夾。裡面分controllers、views和routes。可以把原來的views和routes直接移進去。
在controllers資料夾中新建一個home.js,加入三個方法:index、books和about。
module.exports.index = function(req, res) { res.render('index', { title: 'Index' }); };module.exports.books = function(req, res) { res.render('books', { title: 'Books', }); }; module.exports.about = function (req, res) { res.render('about', { title: 'About' }); };
路由
同樣,在view資料夾中把index.jade複製兩遍,修改為books.jade和about.jade. 然後我們修改routes下的index.js,運用Express框架內附的Router。
var express = require('express');var router = express.Router();var homeController = require('../controllers/home');router.get('/', homeController.index); router.get('/about', homeController.about); router.get('/books', homeController.books);module.exports = router;
這時候還是無法運作的,因為我們改變了目錄結構還沒有在app.js中重新設定。首先設定路由:
var routes = require('./app_server/routes/index'); app.use('/', routes);
修改視圖引擎的起始位置
//app.set('views', path.join(dirname, 'views'));app.set('views', path.join(dirname, 'app_server', 'views'));
dirname代表的是根目錄。然後再瀏覽器訪問/books或/about 。
这样就分离了controller,请求通过路由抵达控制器,控制器将模型数据填充到对应的视图的模板.这就是我们熟悉的MVC模式。我们再看router.METHOD方法定义。
router.METHOD(path, [callback, ...] callback)
这里的METHOD指get,post,put和delete等。因为我们可以定义:
router.get('/book/:bookId', homeController.detail); router.put('/book/:bookId', homeController.updateBook); router.delete('/book/:bookId', homeController.deleteBook);
虽然路径都是一样,但是代表的是不同的用意,完全restful,:bookId表示是参数。
同样支持正则匹配,会匹配类似于这样的‘GET /commits/71dbb9c’
router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res){ var from = req.params[0]; var to = req.params[1] || 'HEAD'; res.send('commit range ' + from + '..' + to); });
如果每个请求都需要做某种处理,可以用all方法:
router.all('*', requireAuthentication, loadUser);
这等价于:
router.all('*', requireAuthentication) router.all('*', loadUser);
Asp.net MVC的路由每一个都需要设置名称,且不能重复出现,且匹配到之后就不再匹配,Express没有这个限制,匹配到之后只要没返回响应就会向下继续传递。相对而言,Express的Router更灵活一些。
更多细节请参考官方API:http://www.expressjs.com.cn/4x/api.html#router
接下来我们回顾下整个app.js。
app.js
var express = require('express');var path = require('path');var favicon = require('serve-favicon');var logger = require('morgan');var cookieParser = require('cookie-parser');var bodyParser = require('body-parser');var routes = require('./app_server/routes/index');var app = express();// view engine setupapp.set('views', path.join(dirname, 'app_server', 'views')); app.set('view engine', 'jade');// uncomment after placing your favicon in /public//app.use(favicon(dirname + '/public/favicon.ico'));app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(require('stylus').middleware(path.join(dirname, 'public'))); app.use(express.static(path.join(dirname, 'public'))); app.use('/', routes);// catch 404 and forward to error handlerapp.use(function (req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); });// error handlers// development error handler// will print stacktraceif (app.get('env') === 'development') { app.use(function (err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); }// production error handler// no stacktraces leaked to userapp.use(function (err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); module.exports = app;
View Code
首先看到很多的require的语法。
var express = require('express');var path = require('path');var favicon = require('serve-favicon');var logger = require('morgan');var cookieParser = require('cookie-parser');var bodyParser = require('body-parser');var routes = require('./app_server/routes/index');
require表示应用一个模块,npm上已经有超过25万个包。这些能直接引用的模块,是已经安装在node_modules文件中。如果是自己定义的模块,比如routes 就要用相对路径。在node中模块分以下几类:
核心模块,如http,fs,path等
.或..开始的相对路径文件模块
以/开始的绝对路径文件模块
非路径形式的文件模块,如自定义的模块。
核心模块会优先加载,以相对或绝对路径加载的模块,require都会转为真实路径,将编译执行后的结果放到缓存中,这样二次加载就会更快。require能加载.js,.node.json的文件,其余扩展名都会被当.js文件载入。模块与文件是一一对应的,一个文件夹的模块就称作包,包通常是一些模块的集合。require是用来获取模块,而exports对象就是用来定义模块。
module.exports.hello = function() { console.log('Hello.'); };
相当于是定义接口,给外部调用。而上面的路由就是把一整个对象封装到模块中。
module.exports = router;
在app.js中直接获取到整个路由对象:
var routes = require('./app_server/routes/index');
看到module.exports直接赋值router有点奇怪,会想不会覆盖掉其他的模块吗,但事实上在编译的过程中,node会对获取的JavaScript文件内容进行包装,等于是每个文件之间都进行了作用域的隔离。
app.js中用set方法设置了路由起始路径和视图引擎。
app.set('views', path.join(dirname, 'app_server', 'views'));//这里我们修改了路径在app_server文件夹下 app.set('view engine', 'jade');//默认的视图引擎是jade
还可以设置路由是否忽略大小写,默认是不忽略。
app.set('case sensitive routing',true)
还可以设置环境变量是开发环境还是生产环境,更多的设置可以参考官方文档:http://www.expressjs.com.cn/4x/api.html#app.settings.table
use方法是用来注册一系列中间件,监听端口上的请求,中间件利用了尾触发机制,每个中间件传递请求对象,响应对象和尾触发函数,通过队列形成一个处理流。
最简单的中间件形式:
app.use(function (req, res, next) { console.log('Time: %d', Date.now()); next(); })
看下各个中间件的作用:
app.use(logger('dev')); //日志,在开发环境下用彩色输出响应状态,会显示请求方式,响应时间和大小。 app.use(bodyParser.json());//解析json请求。 app.use(bodyParser.urlencoded({ extended: false }));//解析form请求(含有key-value键值对),false表示value的类型是string或array,为true表示任意类型。 app.use(cookieParser());//解析cookie app.use(require('stylus').middleware(path.join(dirname, 'public')));//使用stylus做css预编译,并指定路径。 app.use(express.static(path.join(dirname, 'public')));//静态文件路径
我们看到在设置了路由之后,如果请求还没返回则认为页面没有找到,这个时候app抛出一个error。并继续往下传递
app.use('/', routes);// catch 404 and forward to error handlerapp.use(function (req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); });
而接下来,对错误进行了处理
// 开发环境错误处理// 会打印出错误堆栈if (app.get('env') === 'development') { app.use(function (err, req, res, next) { res.status(err.status || 500);//如果不是404就认为是内部错误 res.render('error', { message: err.message, error: err }); }); }// 生产环境错误处理// no stacktraces leaked to userapp.use(function (err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); });
检测到异常的时候,就渲染error模板。 接下来看下error模板,简单介绍下jade语法:
extends layout //相当于Asp.net MVC 设置Layout block content //相当于 Asp.net MVC RenderBody h1= message //显示message h2= error.status //显示错误状态 pre #{error.stack} //错误堆栈
这样就能处理404和500错误页面。
小結:至此,整個預設工程已經介紹完,這一節透過Express框架建立一個基本的MVC工程,了解基本的請求和回應,node的基本模組和中間件;並初步設定了路由,建立起專門的controller;解讀了app.js中的相關程式碼;下一節關注模型和視圖。時至今日,node的開發環境已經很完善,從09年到現在這個技術已經走過了7年了,已經有很多書籍資料,國內的cnode社群很活躍。如果把技術比喻成股票的話,java,C#,PHP這些無疑是大盤白馬股,學這樣的技術風險小,不愁找不到工作。而node這樣的就像創業板股票,你也許認為這有很大的泡沫,認為新的公司不過是炒概念,但他就是在快速成長。
相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!
推薦閱讀:
JavaScript的var與this,{}與function
以上是Nodejs路由與控制器的使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!