node.js Web應用框架Express入門指南
做者: 字體:[增長 減少] 類型:轉載 時間:2014-05-28 我要評論javascript
1、安裝php
或者在任何地方使用可執行的 express(1) 安裝:
$ npm install -g express
2、快速上手html
最快上手 express 的方法是利用可執行的 express(1) 來生成一個應用,以下所示:java
建立一個 app:node
$ npm install -g express
$ express /tmp/foo && cd /tmp/foo
安裝依賴包:
$ npm install -d
啓動服務器:
$ node app.js
3、建立一個服務器jquery
要建立一個 express.HTTPServer 實例,只需調用 createServer() 方法。 通用這個應用實例,咱們能夠定義基於 HTTP 動做(HTTP Verbs)的路由,以 app.get() 爲例:正則表達式
var app = require('express').createServer();
app.get('/', function(req, res){
res.send('hello world');
});redis
app.listen(3000);數據庫
4、建立一個 HTTPS 服務器express
如上述初始化一個 express.HTTPSServer 實例。而後咱們給它傳一個配置對象,接受 key、cert 和其餘在 https 文檔 所提到的(屬性/方法)。
var app = require('express').createServer({ key: ... });
5、配置
Express 支持任意環境,如產品階段(production)和開發階段(development)。開發者可使用 configure() 方法來設置當前所需環境。若是 configure() 的調用不包含任何環境名,它將運行於全部環境中所指定的回調。
譯註: 像 production / development / stage 這些別名都是能夠自已取的,如 application.js 中的 app.configure 所示。實際用法看下面例子。
下面這個例子僅在開發階段 dumpExceptions (拋錯),並返回堆棧異常。不過在兩個環境中咱們都使用 methodOverride 和 bodyParser。注意一下 app.router 的使用,它能夠(可選)用來加載(mount)程序的路由,另外首次調用 app.get()、app.post() 等也將會加載路由。
app.configure(function(){
app.use(express.methodOverride());
app.use(express.bodyParser());
app.use(app.router);
});
app.configure('development', function(){
app.use(express.static(__dirname + '/public'));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
var oneYear = 31557600000;
app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
app.use(express.errorHandler());
});
對於類似的環境你能夠傳遞多個環境字符串:
app.configure('stage', 'prod', function(){
// config
});
對於任何內部設置(#),Express 提供了 set(key[, val])、 enable(key) 和 disable(key) 方法:
譯註:設置詳見:application.js 的 app.set。
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('views');
// => "/absolute/path/to/views"
app.enable('some feature');
// 等價於:app.set('some feature', true);
app.disable('some feature');
// 等價於:app.set('some feature', false);
app.enabled('some feature')
// => false
});
變動環境咱們能夠設置 NODE_ENV 環境變量,如:
$ NODE_ENV=production node app.js
這很是重要,由於多數緩存機制只在產品階段是被打開的。
6、設置
Express 支持下列快捷(out of the box)設置:
1.basepath 用於 res.redirect() 的應用程序基本路徑(base path),顯式地處理綁定的應用程序(transparently handling mounted apps.)
2.view View 默認的根目錄爲 CWD/views
3.view engine 默認 View 引擎處理(View 文件)並不須要使用後綴
4.view cache 啓用 View 緩存 (在產品階段被啓用)
5.charet 改變編碼,默認爲 utf-8
6.case sensitive routes 路由中區分大小寫
7.strit routing 啓用後(路由中的)結尾 / 將不會被忽略(譯註:即 app.get('/sofish') 和 app.get('/sofish/') 將是不同的)
8.json callback 啓用 res.send() / res.json() 顯式的 jsonp 支持(transparent jsonp support)
7、路由
Express 利用 HTTP 動做提供一套提示性強、有表現力的路由 API。打個比方,若是想要處理某個路徑爲 /user/12 的帳號,咱們能像下面這樣來定義路由。關聯到命名佔位符(named placeholders)的值可用 req.params 來訪問。
app.get('/user/:id', function(req, res){
res.send('user ' + req.params.id);
});
路由是一個在內部被編譯爲正則的字符串。譬如,當 /user/:id 被編譯,一個簡化版本的正則表達弄大概以下:
// 修改一下官方的這個字符串
/\/user\/([^\/]+)\/?/
正則表達式能夠傳入應用於複雜的場景。因爲經過字面量正則表達式捕獲的內容組是匿名的,咱們可能直接經過 req.params 來訪問它們。所以,咱們捕獲的第一組內容將是 req.params[0],同時第二組是緊接着的 req.params[1]。
app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res){
res.send(req.params);
});
Curl 針對上述定義路由的請求:
$ curl http://dev:3000/user
[null,null]
$ curl http://dev:3000/users
[null,null]
$ curl http://dev:3000/users/1
["1",null]
$ curl http://dev:3000/users/1..15
["1","15"]
下面是一些路由的實例,關聯到他們可能使用到的路徑:
"/user/:id"
/user/12
"/users/:id?"
/users/5
/users
"/files/*"
/files/jquery.js
/files/javascripts/jquery.js
"/file/*.*"
/files/jquery.js
/files/javascripts/jquery.js
"/user/:id/:operation?"
/user/1
/user/1/edit
"/products.:format"
/products.json
/products.xml
"/products.:format?"
/products.json
/products.xml
/products
"/user/:id.:format?"
/user/12
/user/12.json
舉個例子,咱們可使用 POST 發送 json 數據,經過 bodyParser 這個能夠解析 json 請求內容(或者其餘內容)的中間件來返回數據,並將返回結果存於 req.body 中:
var express = require('express')
, app = express.createServer();
app.use(express.bodyParser());
app.post('/', function(req, res){
res.send(req.body);
});
app.listen(3000);
一般咱們可使用一個像 user/:id 這樣,沒有(命名)限制的「傻瓜」式的佔位符。然而比方說,咱們要限制用戶 id 只能是數字,那麼咱們可能使用 /user/:id([0-9]+),這個將僅當佔位符是包含至少一位數字時才生效(適配,match)。
8、進路控制(Passing Route Control)
咱們能夠經過調用第三個參數,next() 函數,來控制下一個適配的路由。若是找不到適配,控制權將會傳回給 Connect,同時中間件將會按在 use() 中添加的順序被依次調用。道理一樣適應於多個定義到同一路徑的路由,他們將會依次被調用直到其中某個不調用 next() 而決定作出請求響應。
app.get('/users/:id?', function(req, res, next){
var id = req.params.id;
if (id) {
// do something
} else {
next();
}
});
app.get('/users', function(req, res){
// do something else
});
app.all() 方法只調用一次就能夠方便地把一樣的邏輯到全部 HTTP 動做。下面咱們使用它來從僞數據中提取一個用戶,將其賦給 req.user。
var express = require('express')
, app = express.createServer();
var users = [{ name: 'tj' }];
app.all('/user/:id/:op?', function(req, res, next){
req.user = users[req.params.id];
if (req.user) {
next();
} else {
next(new Error('cannot find user ' + req.params.id));
}
});
app.get('/user/:id', function(req, res){
res.send('viewing ' + req.user.name);
});
app.get('/user/:id/edit', function(req, res){
res.send('editing ' + req.user.name);
});
app.put('/user/:id', function(req, res){
res.send('updating ' + req.user.name);
});
app.get('*', function(req, res){
res.send(404, 'what???');
});
app.listen(3000);
9、中間件
使用的 Connect 中間件(屬性)一般伴隨着你的一個常規 Connect 服務器,被傳到 express.createServer() 。如:
var express = require('express');
var app = express.createServer(
express.logger()
, express.bodyParser()
);
另外,在 configure() 塊內 —— 這個漸進式的宮殿(譯註:笑^^,in a progressive manner),咱們還能夠方便地使用 use() 來添加中間件。
app.use(express.logger({ format: ':method :url' }));
一般,使用 connect 中間件你可能會用到 require('connect'),像這樣:
var connect = require('connect');
app.use(connect.logger());
app.use(connect.bodyParser());
這在某種程度上來講有點不爽,因此 express 重導出(re-exports)了這些中間件屬性,儘管他們是同樣的:
app.use(express.logger());
app.use(express.bodyParser());
中間件的順序很是重要,當 Connect 收到一個請求,咱們傳到 createServer() 或者 use() 執行的第一個中間件將附帶三個參數,request、response,以及一個回調函數(一般是 next)。當 next() 被調用,將輪到第二個中間件,依此類推。之因此說這是值得注意的,是由於不少中間件彼此依賴,例如 methodOverride() 查詢 req.body 方法來檢測 HTTP 方法重載,另外一方面 bodyParser() 解析請求內容並將其於寄存於 req.body。另外一個例子是 cookie 解析和 session 支持,咱們必須先 use() cookieParser() 緊接着 session()。
不少 Express 應用都包含這樣的一行 app.use(app.router),這看起來可能有點奇怪,其實它僅僅是一個包含全部定義路由規則,並執行基於現有 URL 請求和 HTTP 方法路由查找的一箇中間件功能。Express 容許你決定其位置(to position),不過默認狀況下它被放置於底部。經過改變路由的位置,咱們能夠改變中間件的優先級,譬如咱們想把錯誤報告作爲最後的中間件,以便任何傳給 next() 的異常均可以經過它來處理;又或者咱們但願靜態文件服務優先級更低,以容許咱們的路由能夠監聽單個靜態文件請求的下載次數,等等。這看起來差很少是這樣的:
app.use(express.logger(...));
app.use(express.bodyParser(...));
app.use(express.cookieParser(...));
app.use(express.session(...));
app.use(app.router);
app.use(express.static(...));
app.use(express.errorHandler(...));
首先咱們添加 logger(),它可能包含 node 的 req.end() 方法,提供咱們響應時間的數據。接下來請求的內容將會被解析(若是有數據的話),緊接着的是 cookie 解析和 session 支持,同時 req.session 將會在觸發 app.router 中的路由時被定義,這時咱們並不調用 next(),所以 static() 中間件將不會知道這個請求,如若已經定義了以下一個路由,咱們則能夠記錄各類狀態、拒絕下載和消耗下載點數等。
var downloads = {};
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.get('/*', function(req, res, next){
var file = req.params[0];
downloads[file] = downloads[file] || 0;
downloads[file]++;
next();
});
10、路由中間件
路由能夠利用路由器中間件,傳遞一個以上的回調函數(或者數組)到其方法中。這個特性很是有利於限制訪問、經過路由下載數據,等等。
一般異步數據檢索看起來可能像下例,咱們使用 :id 參數,嘗試加載一個用戶:
app.get('/user/:id', function(req, res, next){
loadUser(req.params.id, function(err, user){
if (err) return next(err);
res.send('Viewing user ' + user.name);
});
});
爲保證 DRY 原則和提高可讀,咱們能夠把這個邏輯應用於一箇中間件內。以下所示,抽象這個邏輯到中間件內將容許你重用它,同時保證了咱們路由的簡潔。
function loadUser(req, res, next) {
// You would fetch your user from the db
var user = users[req.params.id];
if (user) {
req.user = user;
next();
} else {
next(new Error('Failed to load user ' + req.params.id));
}
}
app.get('/user/:id', loadUser, function(req, res){
res.send('Viewing user ' + req.user.name);
});
多重路由能夠,並按順序應用到更深一層的邏輯,如限制一個用戶帳號的訪問。下面的例子只容許經過鑑定的用戶才能夠編輯他(她)的帳號。
function andRestrictToSelf(req, res, next) {
req.authenticatedUser.id == req.user.id
? next()
: next(new Error('Unauthorized'));
}
app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){
res.send('Editing user ' + req.user.name);
});
時刻銘記路由只是簡單的函數,以下所示,咱們能夠定義返回中間件的函數以建立一個更具表現力,更靈活的方案。
function andRestrictTo(role) {
return function(req, res, next) {
req.authenticatedUser.role == role
? next()
: next(new Error('Unauthorized'));
}
}
app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
res.send('Deleted user ' + req.user.name);
});
經常使用的中間件「堆棧」能夠經過一個數組來傳遞(會被遞歸應用),這些中間件能夠混着、匹配到任何層次(which can be mixed and matched to any degree)。
var a = [middleware1, middleware2]
, b = [middleware3, middleware4]
, all = [a, b];
app.get('/foo', a, function(){});
app.get('/bar', a, function(){});
app.get('/', a, middleware3, middleware4, function(){});
app.get('/', a, b, function(){});
app.get('/', all, function(){});
對於這個實例的完整代碼,請看 route middleware example 這個倉庫。
咱們可能會有屢次想要「跳過」剩餘的路由中間件,繼續匹配後續的路由。作到這點,咱們只需調用 next() 時帶上 'route' 字符串 —— next('route')。若是沒有餘下的路由匹配到請求的 URL,Express 將會返回 404 Not Found。
11、HTTP 方法
至此已接觸了好幾回 app.get(),除此這外 Express 還提供了其餘常見的 HTTP 動做,如 app.post() 、app.del() 等等。
POST 用法的一個經常使用例子是提交一個表單。下面咱們簡單地在 html 中把表單的 method 屬性設置爲 post,控制權將會指派給它下面所定義的路由。
<form method="post" action="/">
<input type="text" name="user[name]" />
<input type="text" name="user[email]" />
<input type="submit" value="Submit" />
</form>
默認上 Express 並不知道如何處理這個請求的內容,所以咱們必須添加 bodyParser 中間件,它將解析 application/x-www-form-urlencoded 和 application/json 請求的內容,並把變量存放於 req.body 中。咱們能夠像下述示例同樣來使用這個中間件:
app.use(express.bodyParser());
以下,咱們的路由將有權訪問 req.body.user 對象,當有 name 和 email 被定義時它將包含這兩個屬性(譯註:若是表單發送的內容不爲空的話)。
app.post('/', function(req, res){
console.log(req.body.user);
res.redirect('back');
});
當想在一個表單中使用像 PUT 這樣的方法,咱們可使用一個命名爲 _method 的 hidden input,它能夠用以修改 HTTP 方法。爲了作這個,咱們首先須要 methodOverride 中間件,它必須出現於 bodyParser 後面,以便使用它的 req.body中所包含的表單值。
app.use(express.bodyParser());
app.use(express.methodOverride());
對於這些方法爲什麼不是默認擁有,簡單來講只是由於它並非 Express 所要求完整功能所必須。方法的使用依賴於你的應用,你可能並不須要它們,客戶端依然能使用像 PUT 和 DELETE 這樣的方法,你能夠直接使用它們,由於 methodOverride 爲 form 提供了一個很是不錯的解決方案。下面將示範如何使用 PUT 這個方法,看起來可能像:
<form method="post" action="/">
<input type="hidden" name="_method" value="put" />
<input type="text" name="user[name]" />
<input type="text" name="user[email]" />
<input type="submit" value="Submit" />
</form>
app.put('/', function(){
console.log(req.body.user);
res.redirect('back');
});
12、錯誤處理
Express 提供了 app.error() 方法以便接收到的異常在一個路由裏拋出,或者傳到 next(err) 中。下面這個例子將基於特定的 NotFound 異常處理不一樣的頁面:
function NotFound(msg){
this.name = 'NotFound';
Error.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
}
NotFound.prototype.__proto__ = Error.prototype;
app.get('/404', function(req, res){
throw new NotFound;
});
app.get('/500', function(req, res){
throw new Error('keyboard cat!');
});
以下述,咱們能夠屢次調用 app.error()。這裏咱們檢測 NotFound 的實例,並顯示 404 頁面,或者傳到 next 錯誤處理器。值得注意的是這些處理器能夠在任何地方定義,由於他們將會在 listen() 的時候被放置於路由處理器下面。它容許在 configure() 塊內有定義,以便咱們能基於環境用不一樣的異常處理方式。
app.error(function(err, req, res, next){
if (err instanceof NotFound) {
res.render('404.jade');
} else {
next(err);
}
});
爲求簡潔(for the simplicity),這裏咱們假定這個 demo 的全部錯誤爲 500,固然你能夠能夠選擇本身喜歡的。像 node 執行文件系統的系統調用時,你可能會接收到一個帶有 ENOENT 的 error.code,意思爲 「不存在這樣的文件或目錄」 的錯誤,咱們能夠在錯誤處理器中使用,或者當有須要時可顯示一個指定的頁面。
app.error(function(err, req, res){
res.render('500.jade', {
error: err
});
});
咱們的 app 一樣能夠利用 Connect 的 errorHandler 中間件來彙報異常。譬如當咱們但願在 「開發」 環境輸出 stderr 異常時,咱們可使用:
app.use(express.errorHandler({ dumpExceptions: true }));
同時在開發階段咱們可能須要在花哨的 HTML 頁面顯示咱們傳遞和拋出的異常,對此咱們能夠把 showStack 設置爲 true。
app.use(express.errorHandler({ showStack: true, dumpExceptions: true }));
errorHandler 中間件還能夠在 Accept: application/json 存在的時候返回 json,這對於開發重度依賴客戶端 Javascript 的應用很是有用。
十3、Route 參數預處理
路由參數預處理,經過隱式數據加載和請求驗證,能夠大大提高你程序的可讀性。打個比方,你一般須要持續地從多個路由獲取基本數據。像用 /user/:id 加載一個用戶,一般來講咱們可能會這樣幹:
app.get('/user/:userId', function(req, res, next){
User.get(req.params.userId, function(err, user){
if (err) return next(err);
res.send('user ' + user.name);
});
});
經過預處理,咱們的參數能夠映射到執行驗證、控制(coercion),甚至從數據庫加載數據的回調。以下咱們帶着參數名調用 app.param() 但願將其映射於某些中間件。如你所見,咱們接受表明佔位符值的 id 參數。使用這個,咱們如常加載用戶並處理錯誤,以及簡單地調用 next() 來把控制權交由下一個預處理或者路由處理器。
app.param('userId', function(req, res, next, id){
User.get(id, function(err, user){
if (err) return next(err);
if (!user) return next(new Error('failed to find user'));
req.user = user;
next();
});
});
一旦這樣作,上所述將會大大地提高路由的可讀性,而且容許咱們輕鬆地在整個程序中共享邏輯:
app.get('/user/:userId', function(req, res){
res.send('user ' + req.user.name);
});
十4、View 處理
View 文件件使用 <name>.<engine> 這樣的格式,其中 <engine> 是被 require 進來模塊的名。例如 layout.ejs 將告訴 view 系統去 require('ejs'),被加載的模塊必須(導出) exports.compile(str, options) 方法,並返回一個 Function 來適應 Express。app.register() 可用以改變這種默認行爲,將文件擴展名映射到特定的引擎。譬如 「foo.html」 能夠由 ejs 來處理。
下面這個例子使用 Jade 來處理 index.html。由於咱們並未使用 layout: false,index.jade 處理後的內容將會被傳入到 layout.jade 中一個名爲 body 的本地變量。
app.get('/', function(req, res){
res.render('index.jade', { title: 'My Site' });
});
新的 view engine 設置容許咱們指定默認的模板引擎,例如當咱們使用 jade 時能夠這樣設置:
app.set('view engine', 'jade');
容許咱們這樣處理:
res.render('index');
對應於:
res.render('index.jade');
當 view engine 被設定,擴展名實屬可選,但咱們依然能夠混着匹配模板引擎:
res.render('another-page.ejs');
Express 同時還提供了 view options 設置,這將應用於一個 view 每次被渲染的時候,譬如你不但願使用 layouts 的時候可能會這樣作:
app.set('view options', {
layout: false
});
在須要的時候,這能夠在 res.render() 調用的內部進行重載:
res.render('myview.ejs', { layout: true });
當有須要變動一個 layout,咱們一般須要再指定一個路徑。譬如當咱們已經把 view engine 設置爲 jade,而且這個文件命名爲 ./views/mylayout.jade,咱們能夠這樣簡單地進行傳參:
res.render('page', { layout: 'mylayout' });
不然(譯註:沒有把 view engine 設置爲 jade 或者其餘的引擎時),咱們必須指定一個擴展名:
res.render('page', { layout: 'mylayout.jade' });
它們一樣能夠是絕對路徑:
res.render('page', { layout: __dirname + '/../../mylayout.jade' });
對於這點有一個不錯的例子 —— 自定義 ejs 的起始和閉合標籤:
app.set('view options', {
open: '{{',
close: '}}'
})
十5、View 部件
Express 的 view 系統內置了部件(partials) 和集合器(collections)的支持,至關於用一個 「迷你」 的 view 替換一個文檔碎片(document fragment)。示例,在一個 view 中重複渲染來顯示評論,咱們可使用部件集:
partial('comment', { collection: comments });
若是並不須要其餘選項或者本地變量,咱們能夠省略整個對象,簡單地傳進一個數組,這與上述是等價的:
partial('comment', comments);
在使用中,部件集無償地提供了一些 「神奇」 本地變量的支持:
1.firstInCollection true,當它是第一個對象的時候
2.indexInCollection 在集合器對象中的索引
3.lastInCollection true,當它是最後一個對象的時候
4.collectionLength 集合器對象的長度
本地變量的傳遞(生成)具有更高的優先級,同時,傳到父級 view 的本地變量對於子級 view 一樣適應。例如當咱們用 partial('blog/post', post) 來渲染一個博客文章,它將會生成一個 post 本地變量,在調用這個函數的 view 中存在本地變量 user,它將一樣對 blog/post 有效。(譯註:這裏 partial 比較像 php 中的 include 方法)。
注意: 請謹慎使用部件集合器,渲染一個長度爲 100 的部件集合數組至關於咱們須要處理 100 個 view。對於簡單的集合,最好重複內置,而非使用部件集合器以免開銷過大。
十6、View 查找
View 查找相對於父級 view (路徑)執行,如咱們有一個 view 頁面叫做 views/user/list.jade,而且在其內部寫有 partial('edit') 則它會嘗試加載 views/user/edit.jade,同理 partial('../messages') 將會加載 views/messages.jade。
View 系統還支持模板索引,容許你使用一個與 view 同名的目錄。例如在一個路由中,res.render('users') 獲得的非 views/users.jade 即 views/users/index.jade。(譯註:先處理 <path>.<engine> 的狀況,再處理 <path>/<index.<engine> 的狀況,詳情可見 view.js。)
當使用上述 view 索引,咱們在與 view 同一個目錄下,使用 partial('users') 中引用 views/users/index.jade,與此同時 view 系統會嘗試索引 ../users/index,而無須咱們調用 partial('users')。
十7、Template Engines
下列爲 Express 最經常使用的模板引擎:
1.Haml:haml 實現
2.Jade:haml.js 繼位者
3.EJS:嵌入式 JavaScript
4.CoffeeKup:基於 CoffeeScript 的模板
5.jQuery Templates
十8、Session 支持
Session 支持能夠經過使用 Connect 的 session 中間件來得到,爲此一般咱們同時須要在其前加上 cookieParser 中間件,它將解析和存儲 cookie 數據於 req.cookies 中。
app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat" }));
默認狀況下 session 中間件使用 Connect 內置的內存存儲,然而還有其餘多種實現方式。如 connect-redis 提供了一種 Redis 的 session 存儲,它這可像下面這樣被使用:
var RedisStore = require('connect-redis')(express);
app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
至此,req.session 和 req.sessionStore 屬性將能夠被全部路由和後繼的中間件使用。在 req.session 上的全部屬性都會在一個響應中被自動保存下來,譬如當咱們想要添加數據到購物車:
var RedisStore = require('connect-redis')(express);
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
app.post('/add-to-cart', function(req, res){
// 咱們可能經過一個表單 POST 出多個 item
// (在些使用 bodyParser() 中間件)
var items = req.body.items;
req.session.items = items;
res.redirect('back');
});
app.get('/add-to-cart', function(req, res){
// 當返回時,頁面 GET /add-to-cart
// 咱們能夠檢查 req.session.items && req.session.items.length
// 來打印出提示
if (req.session.items && req.session.items.length) {
req.notify('info', 'You have %s items in your cart', req.session.items.length);
}
res.render('shopping-cart');
});
對於 req.session 對旬,它還有像 Session#touch()、Session#destroy()、 Session#regenerate() 等用以維護和操做 session 的方法。更多的詳情請看 Connect Session 的文檔。
十9、升級指南
對於使用 Express 1.x 的同窗,若是你有很重要的程序須要升級到 2.x 以得到更好的支持,請看官方很是詳細的遷移指南:http://expressjs.com/guide.html#migration-guide