使用的入門教程是《Node.js開發指南》,其中使用的express版本較老。從安裝開始就出現問題。到第五章的時候,基本沒法按書中走下去了。這里按新的express版本做試驗。
安裝express
npm安裝express,-g指令進行全局安裝:
# npm install -g express
安裝express-generator包
在很久很久以前,那時候express的版本還不到4.0,那時候安裝完express后就可以通過express --help
試用express命令了。一切如同書中所說的那么美好。但如果現在你還照著書上說的那么做,控制臺會告訴你沒有express
這種東西,直接把你雷的外焦里嫩。
歷史發展到現在,那一切已經不好使了。想要使用express
指令,實際上還需要安裝一個叫express-generator的東西。
# npm install -g express-generator
Okey,現在可以愉快的使用express指令了。
建立app
千萬別以為可以正常的使用express指令就可以順利的繼續照著《Node.js開發指南》學習了,狗血的情節不止出現在電影里,還有程序員的屏幕里。
- 首先是你會發現創建好的app需要的依賴比書的多了不止一倍;
- 第二你又發現書中的
express -t ejs microblog
指令根本不好使,創建出來的模版引擎照樣是jade
。 - 第三你最后還發現了用
$node app.js
指令后,啥事也沒發生。
好吧,我們一件一件來。關于現在用express創建的app的依賴,現在是多了很多東西,其實是一個真實工業應用所具備的基礎,以前的express沒有那么成熟,所以沒有,但現在它會自動的創建出來,我們可以先無視它,反正多上這些也不會讓你的硬盤爆炸。
如果要使用ejs代替jade,現在不需要用-t ejs
了,如果你查下express --help
,它會告訴你直接加上-e
就好,就是這樣:$express -e microblog
。
最后,要讓你的app運行起來,目前以我了解到的可以使用debug的模式,這樣:$ cd microblog
然后這樣:$ debug=microblog ./bin/www
。
這時再打開ie,輸入http://127.0.0.1:3000
,你便可以看見親切的Welcome to Express
啦!
好啦。現在項目創建出來啦,瀏覽器也可以打開啦,接著下去,是不是可以繼續照著書做呢?嗯……,我覺得吧還是算了吧,書里解說的和生成的代碼都是兩回事,還不如到 http://www.expressjs.com.cn上去看看??
文件結構
好吧,為了做事不永遠只做一半,咱還是繼續跟著書繼續往下折騰。人生就是不停的折騰才有意義對吧。
首先咱先看看創建出來的目錄結構:
.
├── app.js
├── bin
│ └── www
├── node_modules
│ ├── body-parser
│ ├── cookie-parser
│ ├── debug
│ ├── ejs
│ ├── express
│ ├── morgan
│ └── serve-favicon
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.ejs
└── index.ejs
-
bin/www 文件簡要
首先程序是從 bin/www 這個文件執行起的。如果你的電腦是linux或者mac,可以在控制臺中查看
file bin/www
,它會跟你說:“bin/www: a node script text executable”,換成咱的話就是:這是個可執行的node腳本。什么叫可執行的node腳本呢?通常我們如果要執行一個node.js的文件,會采用這種形式:
$ node hello.js
,但如果是一個可執行的腳本,則無須使用node
命令,直接這樣:./hello.js
就可以了。如果你要讓你的js文件也變成可執行文件,那只需作兩步工作(windows下無效哦……趕緊買蘋果吧,要不換linux?):1. 在hello.js 文件的開頭加上 `#!/usr/bin/env node`, 2. 在終端中給hello.js加上可執行權限`$ chmod +x hello.js`。 3. 然后你就可以愉快的`$ ./hello.js`啦。
小小的提醒下,如果把默認的
#!/usr/bin/env node
改為#!/usr/bin/env supervisor
,那啟動后每次改代碼可以不用手工重新啟動服務哦。—— 貓式跑題了——
咱回到 bin/www 文件,拜讀一下程序生成的這段代碼:
/** * Create HTTP server. */ var server = http.createServer(app); /** * Listen on provided port, on all network interfaces. */ server.listen(port); server.on('error', onError); server.on('listening', onListening);
很明顯嘛,原來端口是在這里指定的,server也是在這里啟動的。但是有關server啟動的因素,卻是由app這個對象塑造啦。這個app在文件開頭的時候已經指定好
var app = require('../app');
,對照這目錄結構,原來就是根目錄下的app.js文件。 -
app.js 文件簡要
仔細閱讀下 app.js,第11行,發現有個var app = express();
,哈,傳說中的 express 對象原來就在這。bin/www 中http.createServer(app)原來就是通過這個express來構造的。
往下看,其它的先不管,先看這幾段話:// 視圖引擎設置(視圖放這里./views下) app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); // ... ... // 配置靜態文件服務器(客戶端js、css文件放這里,./public下): app.use(express.static(path.join(__dirname, 'public'))); // 路由設置(路由放這里 ./routes下) app.use('/', routes); app.use('/users', users);
從字面上其實很好理解,第一是告訴node視圖在哪里找,第二是說哪兒會有靜態文件,第三就是路由從哪里分析啦。
對照著目錄表,這個新新形象還是蠻清爽的嘛!! -
學著配置個簡單的路由,就是HelloWorld啦
app.js 中指出,跟路由 '/' 是由routes指定的,那么我們來看看routes是什么鬼,查看下routes下,會有個index.js和users.js,怎么會有兩個文件?好吧,我猜是index.js來控制的。不理對不對,先看下index.js再說。var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }); }); module.exports = router;
哈,貌似猜對了。文件中指出了'/' 對應的函數。
那我們也來個Hello World?
在.get 函數后面自己加一個:... ... router.get('/helloworld', function(req, res, next) { res.send('Hello World'); }); ... ...
好,然后我們啟動服務器,試一下
http://127.0.0.1:3000/helloworld
,是不是就看到了清爽的 Hello World呢?????再來一個,加個變量到路徑里面:
/** * :name 作為路徑的變量,可以通過程序獲得。 */ router.get('/hello/:name', function(req, res, next) { res.send('<h1>Welcome!</h1><br />Hello ' + req.params.name); });
在瀏覽器中輸入
http://127.0.0.1:3000/hello/Arthur
看看是不是內容根據路徑上的變量變了呢??在上面的小栗子中,路由的控制函數的參數里頭,都有三個參數,前兩個req 和 res 先不說,可是后面那個next是個什么鬼?
實際上express支持一個同一路徑綁定多個控制器,然后express默認執行檢測到的第一個。如果想讓express執行完第一個后,再執行第二個,這時候next就起到作用啦。如下面的例子:/** * :name 作為路徑的變量,可以通過程序獲得。 */ router.get('/hello/:name', function(req, res, next) { console.log('Say hello to '+ req.params.name); next(); // 執行下一個同名的路由。 }); router.get('/hello/:name', function(req, res, next) { res.send('<h1>Welcome!</h1><br />Hello ' + req.params.name); });
啟動這個服務,你會發現,執行完第一個,程序在終端中打印了信息之后,又在瀏覽器中顯示了信息,兩個路由同時被執行了。
-
模版引擎
在MVC架構中,模版引擎包含在服務器端。控制器得到用戶請求后,從模型獲取數據,調用模版引擎。模版引擎以數據和頁面模版為輸入,生成HTML頁面,然后返回給控制器,由控制器交回客戶端。
在app.js中,我們已經通過下面兩個命令指定了模版的位置以及使用的模版引擎:app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs');
在
routers/index.js
中,我們通過res.render('index', { title: 'Express' });
指定要渲染的模版文件以及要傳進模版的數據,那么一個簡單的頁面就這么建立了。 -
ejs 標簽系統
ejs的標簽系統非常簡單,總共就以下三種標簽:- <% code %> JavaScript代碼
- <%=code %> 顯示替換過 HTML 特殊字符的內容
- <%- code %> 顯示原始 HTML 內容
頁面布局
Express會自動套用views目錄下的layout.ejs布局。這里《node.js開發指南》又開始落后了。按書中的意思,Express創建出來的ejs模版會有一個layout.ejs文件,index.ejs文件只是一個模版片段。實際用Express4.13.4創建出來的項目里,默認layout.ejs和index.ejs是合并在一起的。但并不妨礙我們把它拆成兩個。復雜一個index.ejs,改名為layout.ejs,修改代碼如下:<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <%- body %> </body> </html>
在修改原來的index.ejs:
<h1><%= title %></h1> <p>Welcome to <%= title %></p> <span style="color:red" >This is my test span</span>
運行服務并在瀏覽器中打開
http://127.0.0.1:3000
你會發現效果跟原來的一毛一樣。片段視圖
實際上新的ejs已經取消了partial這個這個視圖助手,只能自己迭代然后使用include關鍵字。
新建一個list.ejs:<!-- list.ejs --> <ul> <% items.forEach(function(listitem) { %> <% include listitem %> <% }) %> </ul>
再為list.ejs建立一個片段視圖,補充
<li>
元素:<!-- listitem.ejs --> <li> <%= listitem %> </li>
模版建好了,那么需要指定一個控制器作為頁面的入口。在
routers/index.js
中添加代碼:// routers/index.js // ... ... /* * 演示片段視圖 */ router.get('/list', function(req, res) { res.render('list', { title: 'List', items : [1991, 'arthur', 'express', 'Node.js'] }); }); //... ...
在瀏覽器中打開
http://127.0.0.1:3000/list
就能看到書中的效果啦。