轉載:http://www.cnblogs.com/zhongweiv/p/nodejs_express_webapp1.html
目錄
前言
經過學習Node.js,基本可以開始動手構建一個網站應用了,先用這一篇了解一些構建網站的知識!
主要是些基礎的東西,這里我們說下 express 項目分析...
先從app.js看起
- app.set(name,value)
把名字為name的項的值設為value,用於設置參數
app.set('views', path.join(__dirname, 'views')); 設置了模版文件夾的路徑;主要清楚__dirname的意思就可以了,它是node.js中的全局變量,表示取當前執行文件的路徑
app.set('view engine', 'ejs'); 設置使用的模版引擎,我們使用的ejs
- app.use([path], function)
用這個方法來使用中間件,因為express依賴於connect,有大量的中間件,可以通過app.use來使用;path參數可以不填,默認為'/' (項目中用到的就不分別解釋了,用到的時候自已查一API的中間件部分)
app.use(express.static(path.join(__dirname, 'public'))); 這一句中可能要注意一下,express.static( )是處理靜態請求的,設置了public文件,public下所有文件都會以靜態資料文件形式返回(如樣式、腳本、圖片素材等文件)
var routes = require('./routes/index');
var users = require('./routes/users');
app.use('/', routes);
app.use('/users', users);
上面代碼表示當用戶使用/訪問時,調用routes,即routes目錄下的index.js文件,其中.js后綴省略,用/users訪問時,調用routes目錄下users.js文件
這就是為什么,我們示例中用http://localhost:8100/訪問是,修改的index.js里的文件代碼可以執行(當然index.js文件中也要寫對應的代碼,才能是我們最終看到的效果)
- app.get(name)
獲取名為name的項的值
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
表示如果是開發環境,處理error時會輸出堆棧信息
- 路由文件index.js
主要看下面這段代碼
router.get('/', function(req, res) {
res.render('index', { title: '<h1>Express</h1>'
,users:[{username: 'Wilson'},
{username: 'Wilson Zhong'},
{username: 'Zhong Wei'}]
});
});
這段表示,router.get表示通過get請求/時,響應后面的function處理,兩個參數分別是request、response;
res.render表示調用模版引擎,解析名字index的模板,傳並傳入了title和users兩個對象做為參數;
為什么它會知道解板views目錄下的index.ejs?而不是其它目錄下的文件,或者后其它后綴名的文件?
原因就是app.js中的設置:
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
而這兩個參數在index.ejs中可以使用,那么加上ejs的部分,就會返回最終生成的頁面展現!
如何去創建路由規則、如何去提交表單並接收表單項的值、如何去給密碼加密、如何去提取頁面公共部分(相當於用戶控件和母版頁)等等...
下面就一步步開始吧^_^!...
新建express項目並自定義路由規則
- 首先用命令行express+ejs創建一個項目sampleEjsPre
cd 工作目錄 express -e sampleEjsPre cd sampleEjsPre && npm install
- 默認會有routes目錄下會有index.js和users.js文件,這里為了不產生其它示例外的困擾,刪除user.js文件
- 打開app.js文件刪除下面兩行代碼
var users = require('./routes/users');
...
app.use('/users', users);
- 在routes目錄下添加subform.js、usesession.js、usecookies.js、usecrypto.js文件,並在對應的js文件中添加如下代碼
subform.jsvar express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res) { res.render('subform', { title: '提交表單及接收參數示例' }); }); module.exports = router; subform.js 代碼
usesession.jsvar express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res) { res.render('usesession', { title: '使用session示例' }); }); module.exports = router; usesession.js 代碼
usecookies.jsvar express = require('express'); var router = express.Router(); router.get('/', function(req, res) { res.render('usecookies', { title: '使用cookies示例' }); }); module.exports = router; usecookies.js 代碼
usecrypto.jsvar express = require('express'); var router = express.Router(); router.get('/', function(req, res) { res.render('usecrypto', { title: '加密字符串示例' }); }); module.exports = router; usecrypto.js 代碼
- 在views目錄下添加subform.ejs、usesession.ejs、usecookies.ejs、usecrypto.ejs文件,並在views目錄下除了error.ejs外所有ejs文件中添加如下代碼
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<a href="/">首頁</a>
<a href="/subform">如何提交表單並接收參數?</a>
<a href="/usesession">如何使用session?</a>
<a href="/usecookies">如何使用cookies?</a>
<a href="/usecrypto">如何字符串加密?</a>
</body>
</html>
- 在app.js文件中添加如下代碼
-
var subform = require('./routes/subform'); var usesession = require('./routes/usesession'); var usecookies = require('./routes/usecookies'); var usecrypto = require('./routes/usecrypto'); ... app.use('/subform', subform); app.use('/usesession', usesession); app.use('/usecookies', usecookies); app.use('/usecrypto', usecrypto);通過URL訪問后,根據路由規則先到哪個文件,這里再說明下(app.js中有如下內容):
app.use([path], function)
用這個方法來使用中間件,因為express依賴於connect,有大量的中間件,可以通過app.use來使用;path參數可以不填,默認為'/' (項目中用到的就不分別解釋了,用到的時候自已查一API的中間件部分)
app.use(express.static(path.join(__dirname, 'public'))); 這一句中可能要注意一下,express.static( )是處理靜態請求的,設置了public文件,public下所有文件都會以靜態資料文件形式返回(如樣式、腳本、圖片素材等文件)
var routes = require('./routes/index'); var users = require('./routes/users'); app.use('/', routes); app.use('/users', users);
上面代碼表示當用戶使用/訪問時,調用自定義變量routes,即 routes 目錄下的 index.js 文件,其中.js后綴省略;
用/users訪問時,調用自定義變量uses,即 routes 目錄下 users.js 文件
這就是為什么,我們示例中用http://localhost:8100/訪問是,修改的index.js里的文件代碼可以執行(當然index.js文件中也要寫對應的代碼,才能是我們最終看到的效果)
- 在app.js中添加8000端口監聽並運行
... app.listen(8000); ...
運行界面如下:

點擊各鏈接都能正常跳轉到對應的頁面!這樣第一步的目錄就算達到了!
如何提取頁面中的公共部分?
在上一步創建的網站中每個頁面都幾乎一樣,現在都只有導航部分?每個頁都要寫?當然不是,我們可以提取出來
- 在views目錄下新建一個nav.ejs文件,並添加如下代碼
<a href="/">首頁</a> <a href="/subform">如何提交表單並接收參數?</a> <a href="/usesession">如何使用session?</a> <a href="/usecookies">如何使用cookies?</a> <a href="/usecrypto">如何字符串加密?</a>
- 把views目錄下index.ejs、subform.ejs、usesession.ejs、usecookies.ejs、usecrypto.ejs修改成如下代碼
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<% include nav %> # 若改為了其他引擎,例如 nav.html, 此處則需寫成 <% include nav.html %>
</body>
</html>
運行頁面,發現和上次運行時沒有作何區別,有了這樣的辦法更有利於減少重復代碼、也更有利於統一布局!
<% include 文件名 %> express提供include來嵌入其它頁,這和html嵌入其它頁類似
如果用過express2.0版本的會發現當時沒有這個include,用的是一個模版文件layout.ejs來布局!
如何提交表單並接收參數?
如果要做一個網站應用,不可避免的會遇到表單的提交及獲取參數的值,下面我們來看看用node.js + express怎么做
先來構建一個表單簡單模擬登錄GET方式提交數據
- 打開subform.ejs文件,修改文件代碼為如下:

<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<% include nav %>
<form>
用戶名:<input type="text" id="txtUserName" name="txtUserName" />
密碼:<input type="password" id="txtUserPwd" name="txtUserPwd" />
<input type="submit" value="提交">
</form>
</body>
</html>
subform.ejs 示例代碼
- 打開subform.js我們試着接收參數值並輸出到控制台

var express = require('express'); var router = express.Router(); router.get('/', function(req, res) { var userName = req.query.txtUserName, userPwd = req.query.txtUserPwd, userName2 = req.param('txtUserName'), userPwd2 = req.param('txtUserPwd'); console.log('req.query用戶名:'+userName); console.log('req.query密碼:'+userPwd); console.log('req.param用戶名:'+userName2); console.log('req.param密碼:'+userPwd2); res.render('subform', { title: '提交表單及接收參數示例' }); }); module.exports = router; subform.js get方式源碼
- 運行,並提交表單 在瀏覽器中運行:http://localhost:8000/subform,輸入表單項並提交,可以發現url發生了變化

可以發現url中出現了我表單中輸入並要提交的值!
我們再看看控制台的輸出

我們完成了GET方式提交表單並接收到了值,不錯^_^!(稍后在后面再去講得到值的方式和區別)
再來在上面的代碼基礎上去修改一下表單的method簡單模擬登錄POST方式提交數據
- 首先修改一下subform.ejs文件中的form標簽,修改為如下:
<form method="post"> ... </form>
- 再在subform.js中添加代碼,接收post提交、接收參數並輸出到控制台
...
router.post('/',function(req, res){
var
userName = req.body.txtUserName,
userPwd = req.body.txtUserPwd,
userName2 = req.param('txtUserName'),
userPwd2 = req.param('txtUserPwd');
console.log('req.body用戶名:'+userName);
console.log('req.body密碼:'+userPwd);
console.log('req.param用戶名:'+userName2);
console.log('req.param密碼:'+userPwd2);
res.render('subform', { title: '提交表單及接收參數示例' });
});
...
- 運行,並提交表單 在瀏覽器中運行:http://localhost:8000/subform,輸入表單項並提交,可以發現url不會發生變化

改為post方式后,會發現不會跟get方式提交一樣在url中出現了表單中輸入並要提交的值!
我們再看看控制台的輸出

OK,我們完成了POST提交表單並接收參數!
再回過頭看看GET和POST方式接收值,從直接效果上來看
req.query:我用來接收GET方式提交參數
req.body:我用來接收POST提交的參數
req.params:兩種都能接收到
大家自行看看Express的Request部分的API: http://expressjs.com/api.html#req.params
這里着重解釋一下req.body,Express處理這個post請求是通過中間件bodyParser,你可以看到app.js中有一塊代碼
...
var bodyParser = require('body-parser');
...
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
...
沒有這個中間件Express就不知道怎么處理這個請求,通過bodyParser中間件分析 application/x-www-form-urlencoded和application/json請求,並把變量存入req.body,這種我們才能夠獲取到!
如何字符串加密?
當我們提交表單后,比如密碼這些敏感信息,不做個加密處理那也太不把用戶私密信息當回事了,Node.js提供了一個加密模塊 Crypto http://nodejs.org/api/crypto.html
下面我們用個示例使用一下
- 打開usecrypto.js,修改代碼為如下:
var express = require('express');
var router = express.Router();
var crypto = require('crypto');
/* GET home page. */
router.get('/', function(req, res) {
res.render('usecrypto', { title: '加密字符串示例' });
});
router.post('/',function(req, res){
var
userName = req.body.txtUserName,
userPwd = req.body.txtUserPwd;
//生成口令的散列值
var md5 = crypto.createHash('md5'); //crypto模塊功能是加密並生成各種散列
var en_upwd = md5.update(userPwd).digest('hex');
console.log('加密后的密碼:'+en_upwd);
res.render('usecrypto', { title: '加密字符串示例' });
});
module.exports = router;
- 打開usecrypto.ejs,修改代碼為如下
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<% include nav %>
<form method="post">
用戶名:<input type="text" id="txtUserName" name="txtUserName" />
密碼:<input type="password" id="txtUserPwd" name="txtUserPwd" />
<input type="submit" value="提交">
</form>
</body>
</html>
- 運行,輸入並提交表單,查看控件台輸出

成功MD5方式加密!
其中用到了createHash(algorithm)方法 ,這是利用給定的算法生成hash對象
Node.js提供的加密模塊功能非常強大,Hash算法就提供了MD5、sha1、sha256等,根據需要去使用
update(data, [input_encoding])方法,可以通過指定的input_encoding和傳入的data數據更新hash對象,input_encoding為可選參數,沒有傳入則作為buffer處理 (input_encoding可為'utf-8'、'ascii'等)
digest([encoding])方法,計算數據的hash摘要值,encoding是可選參數,不傳則返回buffer (encoding可為 'hex'、'base64'等);當調用digest方法后hash對象將不可用;
如何使用session?
Internet通訊協議分為stateful和stateless兩類,對Web開發有一定了解的應該知道,http是stateless協議,客戶端發送請求到服務端建立一個連接,請求得得到響應后連接即中斷,服務器端不會記錄狀態,因此服務器端想
要確定是哪個客戶端提交過來的請求,那就必須要借助一些東西去完成,就是session和cookies,現在我們先說說session,以及在nodejs下使用session !
session存在於服務器端,需要cookies的協助才能完成;服務器端和客戶端通過session id來建立聯系(具體session和cookies怎么協作的,可以自已去補充點相關知識,這里只簡單提一下,不展開了,要不然這篇文章就更雜了^_^!)
express中可以用中間件來使用session,express-session(https://github.com/expressjs/session ) 可以存在內存中,也可以存在mongodb、redis等中...
更多中間件:https://github.com/senchalabs/connect#middleware
下面我們通過示例看看怎么使用session (內存方式)
示例設計思路:使用兩個頁面,一個登錄,兩個頁都判斷是否有這個session,如果有,顯示已登錄,沒有則顯示一個登錄按鈕,點此按鈕,記錄session
- 首先通過npm安裝這個中間件,打開package.json文件,在dependencies節點下添加一個鍵值對 "express-session" : "latest"
"dependencies": {
...,
"express-session" : "latest"
}
lateset:最新的
- cd到項目根目錄下,執行npm install

- 打開app.js,添加如下代碼
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
...
//這里傳入了一個密鑰加session id
app.use(cookieParser('Wilson'));
//使用靠就這個中間件
app.use(session({ secret: 'wilson'}));
...
這些options就不解釋了,通過上面中間件的鏈接,自已看一下
- 我這里使用 usesession 和 usecookies 作示例,修改 js 和 ejs 如下


<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<% include nav %>
<% if(locals.islogin){ %>
用戶已登錄
<% } else { %>
<form method="post">
<input type="submit" value="登錄">
</form>
<% } %>
</body>
</html>
usesession.ejs 和 usecookies.ejs
var express = require('express'); var router = express.Router(); router.get('/', function(req, res) { if(req.session.islogin) { console.log('usesession:' + req.session.islogin); res.locals.islogin = req.session.islogin; } res.render('usesession', { title: '使用session示例' }); }); router.post('/', function(req, res) { req.session.islogin = 'success'; res.locals.islogin = req.session.islogin; res.render('usesession', { title: '使用session示例' }); }); module.exports = router;
var express = require('express'); var router = express.Router(); router.get('/', function(req, res) { if(req.session.islogin) { console.log('usecookies:' + req.session.islogin); res.locals.islogin = req.session.islogin; } res.render('usecookies', { title: '使用cookies示例' }); }); router.post('/', function(req, res) { req.session.islogin = 'success'; res.locals.islogin = req.session.islogin; res.render('usecookies', { title: '使用cookies示例' }); }); module.exports = router; usecookies.js 示例代碼
- 運行並查看
第一次運行時,查看兩個頁,效果如下:


- 點擊登錄按鈕后,再查看這兩個頁


- 關閉瀏覽器,再打開查看這兩個頁,如第5步截圖效果
session的使用成功!
官方示例:https://github.com/visionmedia/express/blob/master/examples/session/index.js
如何使用cookies?
如果是登錄,那常見就是“記錄密碼”或“自動登錄”功能,這個一般用 cookies來完成
cookies存在客戶端,安全性較低,一般要存入加密后的信息;建議要設置使用過期時間或不使用時刪除掉
express也同樣可以用中間件來使用:https://github.com/expressjs/cookie-parser
老套路,通過一個示例了解一下
示例設計思路:在上面session示例的基礎上,在usecookies部分登錄同時記錄cookies,來自動登錄
- 在上面session示例的基礎上修改一下usecookies.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
if(req.cookies.islogin)
{
console.log('usecookies-cookies:' + req.cookies.islogin);
req.session.islogin = req.cookies.islogin;
}
if(req.session.islogin)
{
console.log('usecookies:' + req.session.islogin);
res.locals.islogin = req.session.islogin;
}
res.render('usecookies', { title: '使用cookies示例' });
});
router.post('/', function(req, res) {
req.session.islogin = 'success';
res.locals.islogin = req.session.islogin;
res.cookie('islogin', 'sucess', { maxAge: 60000 });
res.render('usecookies', { title: '使用cookies示例' });
});
module.exports = router;
- 運行訪問 http://localhost:8000/usecookies,點擊登錄按鈕登錄成功並記錄cookies
maxAge為過期時長,毫秒為單位,我設置一分鍾
- 關閉瀏覽器,再次訪問http://localhost:8000/usecookies ,頁面顯示已登錄
- 再次關閉瀏覽器,過一分鍾再訪問http://localhost:8000/usecookies,頁面不再是已登錄,而是顯示登錄按鈕,表示cookies過期,不會自動登錄
cookies的使用到此也成功!
官方示例:https://github.com/visionmedia/express/blob/master/examples/cookies/app.js
如何清除session和cookies?
清除非常簡單,就不用示例說明了,有興趣自已定義個路由規則,試試
//清除cookies
res.clearCookie('islogin');
//清除session
req.session.destroy();
寫在之后
最近比較忙,更新距上了篇時間較長了,本篇東西講的比較雜,講到的也比較有限,主要是為了后來會寫的一個示例打基礎;
本篇內容講到的一些知識點,其實都可以單獨拿一整篇去講,本篇基本原則是為了看了之后能使用;
要想弄清楚原理或者更多的相關知識,自已可以花點時間去了解,或者找點資料去豐富一下,當然也可以留言,在我覺得我沒亂說的情況下我會盡量解答^_^!

