亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

node.js Web應(yīng)用框架Express入門指南

 更新時間:2014年05月28日 09:16:52   作者:  
這篇文章主要介紹了node.js Web應(yīng)用框架Express入門指南,從安裝到各種技術(shù)的應(yīng)用,都進行了講解,是一篇不錯的Express入門教程,需要的朋友可以參考下

一、安裝

復(fù)制代碼 代碼如下:
$ npm install express

或者在任何地方使用可執(zhí)行的 express(1) 安裝:

復(fù)制代碼 代碼如下:
\# 譯注:強烈建議這種方式
$ npm install -g express

二、快速上手

最快上手 express 的方法是利用可執(zhí)行的 express(1) 來生成一個應(yīng)用,如下所示:

創(chuàng)建一個 app:

復(fù)制代碼 代碼如下:

$ npm install -g express
$ express /tmp/foo && cd /tmp/foo

安裝依賴包:
復(fù)制代碼 代碼如下:

$ npm install -d

啟動服務(wù)器:
復(fù)制代碼 代碼如下:

$ node app.js

三、創(chuàng)建一個服務(wù)器

要創(chuàng)建一個 express.HTTPServer 實例,只需調(diào)用 createServer() 方法。 通用這個應(yīng)用實例,我們可以定義基于 HTTP 動作(HTTP Verbs)的路由,以 app.get() 為例:

復(fù)制代碼 代碼如下:

var app = require('express').createServer();

app.get('/', function(req, res){
  res.send('hello world');
});

app.listen(3000);

四、創(chuàng)建一個 HTTPS 服務(wù)器

如上述初始化一個 express.HTTPSServer 實例。然后我們給它傳一個配置對象,接受 key、cert 和其他在 https 文檔 所提到的(屬性/方法)。

復(fù)制代碼 代碼如下:

 var app = require('express').createServer({ key: ... });

五、配置

Express 支持任意環(huán)境,如產(chǎn)品階段(production)和開發(fā)階段(development)。開發(fā)者可以使用 configure() 方法來設(shè)置當前所需環(huán)境。如果 configure() 的調(diào)用不包含任何環(huán)境名,它將運行于所有環(huán)境中所指定的回調(diào)。

譯注: 像 production / development / stage 這些別名都是可以自已取的,如 application.js 中的 app.configure 所示。實際用法看下面例子。

下面這個例子僅在開發(fā)階段 dumpExceptions (拋錯),并返回堆棧異常。不過在兩個環(huán)境中我們都使用 methodOverride 和 bodyParser。注意一下 app.router 的使用,它可以(可選)用來加載(mount)程序的路由,另外首次調(diào)用 app.get()、app.post() 等也將會加載路由。

復(fù)制代碼 代碼如下:

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());
});


對于相似的環(huán)境你可以傳遞多個環(huán)境字符串:
復(fù)制代碼 代碼如下:

app.configure('stage', 'prod', function(){
  // config
});

對于任何內(nèi)部設(shè)置(#),Express 提供了 set(key[, val])、 enable(key) 和 disable(key) 方法:

譯注:設(shè)置詳見:application.js 的 app.set。

復(fù)制代碼 代碼如下:

 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
 });


變更環(huán)境我們可以設(shè)置 NODE_ENV 環(huán)境變量,如:
復(fù)制代碼 代碼如下:

$ NODE_ENV=production node app.js

這非常重要,因為多數(shù)緩存機制只在產(chǎn)品階段是被打開的。

六、設(shè)置

Express 支持下列快捷(out of the box)設(shè)置:

1.basepath 用于 res.redirect() 的應(yīng)用程序基本路徑(base path),顯式地處理綁定的應(yīng)用程序(transparently handling mounted apps.)
2.view View 默認的根目錄為 CWD/views
3.view engine 默認 View 引擎處理(View 文件)并不需要使用后綴
4.view cache 啟用 View 緩存 (在產(chǎn)品階段被啟用)
5.charet 改變編碼,默認為 utf-8
6.case sensitive routes 路由中區(qū)分大小寫
7.strit routing 啟用后(路由中的)結(jié)尾 / 將不會被忽略(譯注:即 app.get('/sofish') 和 app.get('/sofish/') 將是不一樣的)
8.json callback 啟用 res.send() / res.json() 顯式的 jsonp 支持(transparent jsonp support)

七、路由

Express 利用 HTTP 動作提供一套提示性強、有表現(xiàn)力的路由 API。打個比方,如果想要處理某個路徑為 /user/12 的賬號,我們能像下面這樣來定義路由。關(guān)聯(lián)到命名占位符(named placeholders)的值可用 req.params 來訪問。

復(fù)制代碼 代碼如下:

app.get('/user/:id', function(req, res){
    res.send('user ' + req.params.id);
});

路由是一個在內(nèi)部被編譯為正則的字符串。譬如,當 /user/:id 被編譯,一個簡化版本的正則表達弄大概如下:
復(fù)制代碼 代碼如下:

// 修改一下官方的這個字符串
/\/user\/([^\/]+)\/?/

正則表達式可以傳入應(yīng)用于復(fù)雜的場景。由于通過字面量正則表達式捕獲的內(nèi)容組是匿名的,我們可能直接通過 req.params 來訪問它們。因此,我們捕獲的第一組內(nèi)容將是 req.params[0],同時第二組是緊接著的 req.params[1]。
復(fù)制代碼 代碼如下:

app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res){
    res.send(req.params);
});

Curl 針對上述定義路由的請求:
復(fù)制代碼 代碼如下:

$ 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"]

下面是一些路由的實例,關(guān)聯(lián)到他們可能使用到的路徑:
復(fù)制代碼 代碼如下:

"/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 發(fā)送 json 數(shù)據(jù),通過 bodyParser 這個可以解析 json 請求內(nèi)容(或者其他內(nèi)容)的中間件來返回數(shù)據(jù),并將返回結(jié)果存于 req.body 中:
復(fù)制代碼 代碼如下:

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 只能是數(shù)字,那么我們可能使用 /user/:id([0-9]+),這個將僅當占位符是包含至少一位數(shù)字時才生效(適配,match)。

八、進路控制(Passing Route Control)

我們可以通過調(diào)用第三個參數(shù),next() 函數(shù),來控制下一個適配的路由。如果找不到適配,控制權(quán)將會傳回給 Connect,同時中間件將會按在 use() 中添加的順序被依次調(diào)用。道理同樣適應(yīng)于多個定義到同一路徑的路由,他們將會依次被調(diào)用直到其中某個不調(diào)用 next() 而決定做出請求響應(yīng)。

復(fù)制代碼 代碼如下:

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() 方法只調(diào)用一次就可以方便地把同樣的邏輯到所有 HTTP 動作。下面我們使用它來從偽數(shù)據(jù)中提取一個用戶,將其賦給 req.user。
復(fù)制代碼 代碼如下:

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);


九、中間件

使用的 Connect 中間件(屬性)通常伴隨著你的一個常規(guī) Connect 服務(wù)器,被傳到 express.createServer() 。如:

復(fù)制代碼 代碼如下:

var express = require('express');

var app = express.createServer(
      express.logger()
    , express.bodyParser()
  );


另外,在 configure() 塊內(nèi) —— 這個漸進式的宮殿(譯注:笑^^,in a progressive manner),我們還可以方便地使用 use() 來添加中間件。
復(fù)制代碼 代碼如下:

app.use(express.logger({ format: ':method :url' }));

通常,使用 connect 中間件你可能會用到 require('connect'),像這樣:
復(fù)制代碼 代碼如下:

var connect = require('connect');
app.use(connect.logger());
app.use(connect.bodyParser());

這在某種程度上來說有點不爽,所以 express 重導(dǎo)出(re-exports)了這些中間件屬性,盡管他們是一樣的:
復(fù)制代碼 代碼如下:

app.use(express.logger());
app.use(express.bodyParser());

中間件的順序非常重要,當 Connect 收到一個請求,我們傳到 createServer() 或者 use() 執(zhí)行的第一個中間件將附帶三個參數(shù),request、response,以及一個回調(diào)函數(shù)(通常是 next)。當 next() 被調(diào)用,將輪到第二個中間件,依此類推。之所以說這是值得注意的,是因為很多中間件彼此依賴,例如 methodOverride() 查詢 req.body 方法來檢測 HTTP 方法重載,另一方面 bodyParser() 解析請求內(nèi)容并將其于寄存于 req.body。另一個例子是 cookie 解析和 session 支持,我們必須先 use() cookieParser() 緊接著 session()。

很多 Express 應(yīng)用都包含這樣的一行 app.use(app.router),這看起來可能有點奇怪,其實它僅僅是一個包含所有定義路由規(guī)則,并執(zhí)行基于現(xiàn)有 URL 請求和 HTTP 方法路由查找的一個中間件功能。Express 允許你決定其位置(to position),不過默認情況下它被放置于底部。通過改變路由的位置,我們可以改變中間件的優(yōu)先級,譬如我們想把錯誤報告做為最后的中間件,以便任何傳給 next() 的異常都可以通過它來處理;又或者我們希望靜態(tài)文件服務(wù)優(yōu)先級更低,以允許我們的路由可以監(jiān)聽單個靜態(tài)文件請求的下載次數(shù),等等。這看起來差不多是這樣的:

復(fù)制代碼 代碼如下:

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() 方法,提供我們響應(yīng)時間的數(shù)據(jù)。接下來請求的內(nèi)容將會被解析(如果有數(shù)據(jù)的話),緊接著的是 cookie 解析和 session 支持,同時 req.session 將會在觸發(fā) app.router 中的路由時被定義,這時我們并不調(diào)用 next(),因此 static() 中間件將不會知道這個請求,如若已經(jīng)定義了如下一個路由,我們則可以記錄各種狀態(tài)、拒絕下載和消耗下載點數(shù)等。
復(fù)制代碼 代碼如下:

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();
});

十、路由中間件

路由可以利用路由器中間件,傳遞一個以上的回調(diào)函數(shù)(或者數(shù)組)到其方法中。這個特性非常有利于限制訪問、通過路由下載數(shù)據(jù),等等。

通常異步數(shù)據(jù)檢索看起來可能像下例,我們使用 :id 參數(shù),嘗試加載一個用戶:

復(fù)制代碼 代碼如下:

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 原則和提升可讀,我們可以把這個邏輯應(yīng)用于一個中間件內(nèi)。如下所示,抽象這個邏輯到中間件內(nèi)將允許你重用它,同時保證了我們路由的簡潔。
復(fù)制代碼 代碼如下:

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);
});


多重路由可以,并按順序應(yīng)用到更深一層的邏輯,如限制一個用戶賬號的訪問。下面的例子只允許通過鑒定的用戶才可以編輯他(她)的賬號。
復(fù)制代碼 代碼如下:

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);
});


時刻銘記路由只是簡單的函數(shù),如下所示,我們可以定義返回中間件的函數(shù)以創(chuàng)建一個更具表現(xiàn)力,更靈活的方案。
復(fù)制代碼 代碼如下:

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);
});


常用的中間件“堆棧”可以通過一個數(shù)組來傳遞(會被遞歸應(yīng)用),這些中間件可以混著、匹配到任何層次(which can be mixed and matched to any degree)。
復(fù)制代碼 代碼如下:

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 這個倉庫。

我們可能會有多次想要“跳過”剩余的路由中間件,繼續(xù)匹配后續(xù)的路由。做到這點,我們只需調(diào)用 next() 時帶上 'route' 字符串 —— next('route')。如果沒有余下的路由匹配到請求的 URL,Express 將會返回 404 Not Found。

十一、HTTP 方法

至此已接觸了好幾次 app.get(),除此這外 Express 還提供了其他常見的 HTTP 動作,如 app.post() 、app.del() 等等。

POST 用法的一個常用例子是提交一個表單。下面我們簡單地在 html 中把表單的 method 屬性設(shè)置為 post,控制權(quán)將會指派給它下面所定義的路由。

復(fù)制代碼 代碼如下:

<form method="post" action="/">
     <input type="text" name="user[name]" />
     <input type="text" name="user[email]" />
     <input type="submit" value="Submit" />
</form>

默認上 Express 并不知道如何處理這個請求的內(nèi)容,因此我們必須添加 bodyParser 中間件,它將解析 application/x-www-form-urlencoded 和 application/json 請求的內(nèi)容,并把變量存放于 req.body 中。我們可以像下述示例一樣來使用這個中間件:
復(fù)制代碼 代碼如下:

app.use(express.bodyParser());

如下,我們的路由將有權(quán)訪問 req.body.user 對象,當有 name 和 email 被定義時它將包含這兩個屬性(譯注:如果表單發(fā)送的內(nèi)容不為空的話)。
復(fù)制代碼 代碼如下:

app.post('/', function(req, res){
  console.log(req.body.user);
  res.redirect('back');
});

當想在一個表單中使用像 PUT 這樣的方法,我們可以使用一個命名為 _method 的 hidden input,它可以用以修改 HTTP 方法。為了做這個,我們首先需要 methodOverride 中間件,它必須出現(xiàn)于 bodyParser 后面,以便使用它的 req.body中所包含的表單值。
復(fù)制代碼 代碼如下:

app.use(express.bodyParser());
app.use(express.methodOverride());

對于這些方法為何不是默認擁有,簡單來說只是因為它并不是 Express 所要求完整功能所必須。方法的使用依賴于你的應(yīng)用,你可能并不需要它們,客戶端依然能使用像 PUT 和 DELETE 這樣的方法,你可以直接使用它們,因為 methodOverride 為 form 提供了一個非常不錯的解決方案。下面將示范如何使用 PUT 這個方法,看起來可能像:
復(fù)制代碼 代碼如下:

<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');
});

十二、錯誤處理

Express 提供了 app.error() 方法以便接收到的異常在一個路由里拋出,或者傳到 next(err) 中。下面這個例子將基于特定的 NotFound 異常處理不同的頁面:

復(fù)制代碼 代碼如下:

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!');
});


如下述,我們可以多次調(diào)用 app.error()。這里我們檢測 NotFound 的實例,并顯示 404 頁面,或者傳到 next 錯誤處理器。值得注意的是這些處理器可以在任何地方定義,因為他們將會在 listen() 的時候被放置于路由處理器下面。它允許在 configure() 塊內(nèi)有定義,以便我們能基于環(huán)境用不同的異常處理方式。
復(fù)制代碼 代碼如下:

app.error(function(err, req, res, next){
    if (err instanceof NotFound) {
        res.render('404.jade');
    } else {
        next(err);
    }
});

為求簡潔(for the simplicity),這里我們假定這個 demo 的所有錯誤為 500,當然你可以可以選擇自己喜歡的。像 node 執(zhí)行文件系統(tǒng)的系統(tǒng)調(diào)用時,你可能會接收到一個帶有 ENOENT 的 error.code,意思為 “不存在這樣的文件或目錄” 的錯誤,我們可以在錯誤處理器中使用,或者當有需要時可顯示一個指定的頁面。
復(fù)制代碼 代碼如下:

app.error(function(err, req, res){
  res.render('500.jade', {
     error: err
  });
});

我們的 app 同樣可以利用 Connect 的 errorHandler 中間件來匯報異常。譬如當我們希望在 “開發(fā)” 環(huán)境輸出 stderr 異常時,我們可以使用:
復(fù)制代碼 代碼如下:

app.use(express.errorHandler({ dumpExceptions: true }));

同時在開發(fā)階段我們可能需要在花哨的 HTML 頁面顯示我們傳遞和拋出的異常,對此我們可以把 showStack 設(shè)置為 true。
復(fù)制代碼 代碼如下:

app.use(express.errorHandler({ showStack: true, dumpExceptions: true }));

errorHandler 中間件還可以在 Accept: application/json 存在的時候返回 json,這對于開發(fā)重度依賴客戶端 Javascript 的應(yīng)用非常有用。

十三、Route 參數(shù)預(yù)處理

路由參數(shù)預(yù)處理,通過隱式數(shù)據(jù)加載和請求驗證,可以大大提升你程序的可讀性。打個比方,你通常需要持續(xù)地從多個路由獲取基本數(shù)據(jù)。像用 /user/:id 加載一個用戶,通常來說我們可能會這樣干:

復(fù)制代碼 代碼如下:

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);
  });
});

通過預(yù)處理,我們的參數(shù)可以映射到執(zhí)行驗證、控制(coercion),甚至從數(shù)據(jù)庫加載數(shù)據(jù)的回調(diào)。如下我們帶著參數(shù)名調(diào)用 app.param() 希望將其映射于某些中間件。如你所見,我們接受代表占位符值的 id 參數(shù)。使用這個,我們?nèi)绯<虞d用戶并處理錯誤,以及簡單地調(diào)用 next() 來把控制權(quán)交由下一個預(yù)處理或者路由處理器。
復(fù)制代碼 代碼如下:

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();
  });
});

一旦這樣做,上所述將會大大地提升路由的可讀性,并且允許我們輕松地在整個程序中共享邏輯:
復(fù)制代碼 代碼如下:

app.get('/user/:userId', function(req, res){
  res.send('user ' + req.user.name);
});


十四、View 處理

View 文件件使用 <name>.<engine> 這樣的格式,其中 <engine> 是被 require 進來模塊的名。例如 layout.ejs 將告訴 view 系統(tǒng)去 require('ejs'),被加載的模塊必須(導(dǎo)出) exports.compile(str, options) 方法,并返回一個 Function 來適應(yīng) Express。app.register() 可用以改變這種默認行為,將文件擴展名映射到特定的引擎。譬如 “foo.html” 可以由 ejs 來處理。

下面這個例子使用 Jade 來處理 index.html。因為我們并未使用 layout: false,index.jade 處理后的內(nèi)容將會被傳入到 layout.jade 中一個名為 body 的本地變量。

復(fù)制代碼 代碼如下:

app.get('/', function(req, res){
    res.render('index.jade', { title: 'My Site' });
});

新的 view engine 設(shè)置允許我們指定默認的模板引擎,例如當我們使用 jade 時可以這樣設(shè)置:
復(fù)制代碼 代碼如下:

app.set('view engine', 'jade');

允許我們這樣處理:
復(fù)制代碼 代碼如下:

res.render('index');

對應(yīng)于:
復(fù)制代碼 代碼如下:

res.render('index.jade');

當 view engine 被設(shè)定,擴展名實屬可選,但我們依然可以混著匹配模板引擎:
復(fù)制代碼 代碼如下:

res.render('another-page.ejs');

Express 同時還提供了 view options 設(shè)置,這將應(yīng)用于一個 view 每次被渲染的時候,譬如你不希望使用 layouts 的時候可能會這樣做:
復(fù)制代碼 代碼如下:

app.set('view options', {
    layout: false
});

在需要的時候,這可以在 res.render() 調(diào)用的內(nèi)部進行重載:
復(fù)制代碼 代碼如下:

res.render('myview.ejs', { layout: true });

當有需要變更一個 layout,我們通常需要再指定一個路徑。譬如當我們已經(jīng)把 view engine 設(shè)置為 jade,并且這個文件命名為 ./views/mylayout.jade,我們可以這樣簡單地進行傳參:
復(fù)制代碼 代碼如下:

res.render('page', { layout: 'mylayout' });

否則(譯注:沒有把 view engine 設(shè)置為 jade 或者其他的引擎時),我們必須指定一個擴展名:
復(fù)制代碼 代碼如下:

res.render('page', { layout: 'mylayout.jade' });

它們同樣可以是絕對路徑:
復(fù)制代碼 代碼如下:

res.render('page', { layout: __dirname + '/../../mylayout.jade' });

對于這點有一個不錯的例子 —— 自定義 ejs 的起始和閉合標簽:
復(fù)制代碼 代碼如下:

app.set('view options', {
    open: '{{',
    close: '}}'
})

十五、View 部件

Express 的 view 系統(tǒng)內(nèi)置了部件(partials) 和集合器(collections)的支持,相當于用一個 “迷你” 的 view 替換一個文檔碎片(document fragment)。示例,在一個 view 中重復(fù)渲染來顯示評論,我們可以使用部件集:

復(fù)制代碼 代碼如下:

partial('comment', { collection: comments });

如果并不需要其他選項或者本地變量,我們可以省略整個對象,簡單地傳進一個數(shù)組,這與上述是等價的:
復(fù)制代碼 代碼如下:

partial('comment', comments);

在使用中,部件集無償?shù)靥峁┝艘恍?“神奇” 本地變量的支持:

1.firstInCollection true,當它是第一個對象的時候
2.indexInCollection 在集合器對象中的索引
3.lastInCollection true,當它是最后一個對象的時候
4.collectionLength 集合器對象的長度

本地變量的傳遞(生成)具備更高的優(yōu)先級,同時,傳到父級 view 的本地變量對于子級 view 同樣適應(yīng)。例如當我們用 partial('blog/post', post) 來渲染一個博客文章,它將會生成一個 post 本地變量,在調(diào)用這個函數(shù)的 view 中存在本地變量 user,它將同樣對 blog/post 有效。(譯注:這里 partial 比較像 php 中的 include 方法)。

注意: 請謹慎使用部件集合器,渲染一個長度為 100 的部件集合數(shù)組相當于我們需要處理 100 個 view。對于簡單的集合,最好重復(fù)內(nèi)置,而非使用部件集合器以避免開銷過大。

十六、View 查找

View 查找相對于父級 view (路徑)執(zhí)行,如我們有一個 view 頁面叫作 views/user/list.jade,并且在其內(nèi)部寫有 partial('edit') 則它會嘗試加載 views/user/edit.jade,同理 partial('../messages') 將會加載 views/messages.jade。

View 系統(tǒng)還支持模板索引,允許你使用一個與 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 系統(tǒng)會嘗試索引 ../users/index,而無須我們調(diào)用 partial('users')。

十七、Template Engines

下列為 Express 最常用的模板引擎:

1.Haml:haml 實現(xiàn)
2.Jade:haml.js 繼位者
3.EJS:嵌入式 JavaScript
4.CoffeeKup:基于 CoffeeScript 的模板
5.jQuery Templates

十八、Session 支持

Session 支持可以通過使用 Connect 的 session 中間件來獲得,為此通常我們同時需要在其前加上 cookieParser 中間件,它將解析和存儲 cookie 數(shù)據(jù)于 req.cookies 中。

復(fù)制代碼 代碼如下:

app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat" }));

默認情況下 session 中間件使用 Connect 內(nèi)置的內(nèi)存存儲,然而還有其他多種實現(xiàn)方式。如 connect-redis 提供了一種 Redis 的 session 存儲,它這可像下面這樣被使用:
復(fù)制代碼 代碼如下:

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 上的所有屬性都會在一個響應(yīng)中被自動保存下來,譬如當我們想要添加數(shù)據(jù)到購物車:
復(fù)制代碼 代碼如下:

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 的文檔。

十九、升級指南

對于使用 Express 1.x 的同學(xué),如果你有很重要的程序需要升級到 2.x 以獲得更好的支持,請看官方非常詳細的遷移指南http://expressjs.com/guide.html#migration-guide

相關(guān)文章

  • js實現(xiàn)圖片點擊左右輪播

    js實現(xiàn)圖片點擊左右輪播

    本文給大家分享的是使用javascript實現(xiàn)的圖片左右輪播的代碼,已經(jīng)封裝完畢,使用方法非常簡單,參考示例,有需要的小伙伴可以參考下。
    2015-07-07
  • 簡潔短小的 JavaScript IE 瀏覽器判定代碼

    簡潔短小的 JavaScript IE 瀏覽器判定代碼

    IE瀏覽器不管是什么版本,總是跟Web標準有些不太兼容。對于代碼工作者來說,自然是苦不堪言,為了考慮IE的兼容問題,不管是寫 CSS 還是 JS,往往都要對 IE 特別對待,這就少不了做些判斷。本文不討論如何區(qū)分 IE 的樣式,僅是 JS 判定 IE 瀏覽器。
    2010-03-03
  • 什么是JavaScript中的結(jié)果值?

    什么是JavaScript中的結(jié)果值?

    你知道JavaScript中的結(jié)果值是什么嗎?這篇文章主要介紹了JavaScript結(jié)果值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • JavaScript中的閉包介紹

    JavaScript中的閉包介紹

    這篇文章主要介紹了JavaScript中的閉包介紹,本文講解了Javacript 閉包、Javscript 閉包與this、Javscript 閉包與讀寫變量等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • uni-app配置APP自定義頂部標題欄設(shè)置方法與注意事項

    uni-app配置APP自定義頂部標題欄設(shè)置方法與注意事項

    相信很多小伙伴在使用uniapp進行多端開發(fā)的時候,在面對一些業(yè)務(wù)需求的時候,uniapp給我們提供的默認導(dǎo)航欄已經(jīng)不能滿足我們的業(yè)務(wù)需求了,這篇文章主要給大家介紹了關(guān)于uni-app配置APP自定義頂部標題欄設(shè)置方法與注意事項的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • 微信小程序 數(shù)據(jù)緩存實現(xiàn)方法詳解

    微信小程序 數(shù)據(jù)緩存實現(xiàn)方法詳解

    這篇文章主要介紹了微信小程序 數(shù)據(jù)緩存實現(xiàn)方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-08-08
  • javascript日期計算實例分析

    javascript日期計算實例分析

    這篇文章主要介紹了javascript日期計算,涉及javascript針對日期計算的相關(guān)技巧,這里需要注意索引的使用,需要的朋友可以參考下
    2015-06-06
  • js拼接字符串時如何在中間加上空格

    js拼接字符串時如何在中間加上空格

    這篇文章主要介紹了js拼接字符串時如何在中間加上空格的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 微信小程序頁面跳轉(zhuǎn)功能之從列表的item項跳轉(zhuǎn)到下一個頁面的方法

    微信小程序頁面跳轉(zhuǎn)功能之從列表的item項跳轉(zhuǎn)到下一個頁面的方法

    這篇文章主要介紹了微信小程序頁面跳轉(zhuǎn)功能之從列表的item項跳轉(zhuǎn)到下一個頁面的方法,結(jié)合具體實例形式總結(jié)分析了微信小程序頁面跳轉(zhuǎn)及列表item項跳轉(zhuǎn)頁面的相關(guān)操作技巧,需要的朋友可以參考下
    2017-11-11
  • 原生js滑動輪播封裝

    原生js滑動輪播封裝

    這篇文章主要為大家詳細介紹了原生js滑動輪播封裝,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07

最新評論