Express 學習筆記

express

第一個 express

開始

mkdir myapp
# 注意設置 默認啟動 js 為app.js
npm init 
npm install express --save

創建 app.js

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

app.get('/', function (req, res) {
  res.send('Hello World!');
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

對所有 (/) URL 或 路由 返回 “Hello World!” 字符串。對于其他所有路徑全部返回 404 Not Found。

啟動

node app.js

使用express 應用生成器

安裝

npm install express-generator -g
# -h 選項可以列出所有可用的命令行選項:
express -h

創建

# 不需要創建myapp目錄,自動創建
express myapp
# 進入myapp 安裝依賴
cd myapp
npm install 
# 啟動
DEBUG=myapp npm start

使用webstorm 創建項目

File--New--Project--Node.js Express App(左側)--配置blabla

express 路由

路由的定義由如下結構組成:app.METHOD(PATH, HANDLER)。其中,app 是一個 express 實例;METHOD 是某個 HTTP 請求方式中的一個;PATH 是服務器端的路徑;HANDLER 是當路由匹配到時需要執行的函數。

get, post, put, head, delete, options, trace, copy, lock, mkcol, move, purge, propfind, proppatch, unlock, report, mkactivity, checkout, merge, m-search, notify, subscribe, unsubscribe, patch, search, 和 connect。

有些路由方法名不是合規的 JavaScript 變量名,此時使用括號記法,比如: app['m-search']('/', function ...

示例[結合postman快速測試吧]:

// 對網站首頁的訪問返回 "Hello World!" 字樣
app.get('/', function (req, res) {
  res.send('Hello World!');
});

// 網站首頁接受 POST 請求
app.post('/', function (req, res) {
  res.send('Got a POST request');
});

// /user 節點接受 PUT 請求
app.put('/user', function (req, res) {
  res.send('Got a PUT request at /user');
});

// /user 節點接受 DELETE 請求
app.delete('/user', function (req, res) {
  res.send('Got a DELETE request at /user');
});

使用字符串模式的路由

在我理解來就是通配符。

// 匹配 acd 和 abcd
app.get('/ab?cd', function(req, res) {
  res.send('ab?cd');
});

// 匹配 abcd、abbcd、abbbcd等
app.get('/ab+cd', function(req, res) {
  res.send('ab+cd');
});

// 匹配 abcd、abxcd、abRABDOMcd、ab123cd等
app.get('/ab*cd', function(req, res) {
  res.send('ab*cd');
});

// 匹配 /abe 和 /abcde
app.get('/ab(cd)?e', function(req, res) {
 res.send('ab(cd)?e');
});

使用正則表達式的路由路徑

// 匹配任何路徑中含有 a 的路徑:
app.get(/a/, function(req, res) {
  res.send('/a/');
});

// 匹配 butterfly、dragonfly,不匹配 butterflyman、dragonfly man等
app.get(/.*fly$/, function(req, res) {
  res.send('/.*fly$/');
});

路由句柄

使用一個回調函數處理路由:

app.get('/example/a', function (req, res) {
  res.send('Hello from A!');
});

使用多個回調函數處理路由(記得指定 next 對象):

app.get('/example/b', function (req, res, next) {
  console.log('response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from B!');
});

使用回調函數數組處理路由:

var cb0 = function (req, res, next) {
  console.log('CB0');
  next();
}

var cb1 = function (req, res, next) {
  console.log('CB1');
  next();
}

var cb2 = function (req, res) {
  res.send('Hello from C!');
}

app.get('/example/c', [cb0, cb1, cb2]);

混合使用函數和函數數組處理路由:

var cb0 = function (req, res, next) {
  console.log('CB0');
  next();
}

var cb1 = function (req, res, next) {
  console.log('CB1');
  next();
}

app.get('/example/d', [cb0, cb1], function (req, res, next) {
  console.log('response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from D!');
});

響應方法

下表中響應對象(res)的方法向客戶端返回響應,終結請求響應的循環。如果在路由句柄中一個方法也不調用,來自客戶端的請求會一直掛起。

方法 描述
res.download() 提示下載文件
res.end() 終結響應處理流程
res.json() 發送一個JSON格式的響應
res.jsonp() 發送一個支持JSONP的JSON格式的響應
res.redirect() 重定向請求
res.render() 渲染視圖模板
res.send() 發送各種類型的響應
res.sendFile() 以八位字節流的形式發送文件
res.sendStatus() 設置響應狀態代碼,并將其以字符串形式作為響應體的一部分發送

app.route()

可使用 app.route() 創建路由路徑的鏈式路由句柄。由于路徑在一個地方指定,這樣做有助于創建模塊化的路由,而且減少了代碼冗余和拼寫錯誤。

app.route('/book')
  .get(function(req, res) {
    res.send('Get a random book');
  })
  .post(function(req, res) {
    res.send('Add a book');
  })
  .put(function(req, res) {
    res.send('Update the book');
  });

express.Route

創建 birds.js

var express = require('express');
var router = express.Router();

// 該路由使用的中間件
router.use(function timeLog(req, res, next) {
  console.log('Time: ', Date.now());
  next();
});
// 定義網站主頁的路由
router.get('/', function(req, res) {
  res.send('Birds home page');
});
// 定義 about 頁面的路由
router.get('/about', function(req, res) {
  res.send('About birds');
});

module.exports = router;

然后在應用中加載路由模塊

var birds = require('./birds');
...
app.use('/birds', birds);

應用即可處理發自 /birds 和 /birds/about 的請求,并且調用為該路由指定的 timeLog 中間件。

利用Express托管靜態文件

通過 Express 內置的 express.static 可以方便地托管靜態文件,例如圖片、CSS、JavaScript 文件等。

app.use(express.static('public'));

現在,public 目錄下面的文件就可以訪問了。

//訪問
http://localhost:3000/images/kitten.jpg

如果你的靜態資源存放在多個目錄下面,你可以多次調用 express.static 中間件:

app.use(express.static('public'));
app.use(express.static('files'));

也可以

app.use('/static', express.static('public'));
//訪問
http://localhost:3000/static/images/kitten.jpg

渲染 html

res.sendFile();

使用中間件

Express 是一個自身功能極簡,完全是由路由和中間件構成一個的 web 開發框架:從本質上來說,一個 Express 應用就是在調用各種中間件。

中間件是一個函數,它可以訪問請求對象req,響應對象res,和web應用中處于請求-響應循環流程中的中間件,一般被命名為next的變量。

中間件的功能:

  • 執行任何代碼
  • 修改請求和響應對象
  • 終結請求-響應循環
  • 調用堆棧中的下一個中間件

如果當前中間件沒有終結請求-響應循環,則必須調用 next() 方法將控制權交給下一個中間件,否則請求就會掛起。

應用級中間件

應用級中間件綁定到 app 對象 使用 app.use() 和 app.METHOD(), 其中, METHOD 是需要處理的 HTTP 請求的方法,例如 GET, PUT, POST 等等,全部小寫。例如:

var app = express();

// 沒有掛載路徑的中間件,應用的每個請求都會執行該中間件
app.use(function (req, res, next) {
  console.log('Time:', Date.now());
  next();
});

// 掛載至 /user/:id 的中間件,任何指向 /user/:id 的請求都會執行它
app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

// 路由和句柄函數(中間件系統),處理指向 /user/:id 的 GET 請求
app.get('/user/:id', function (req, res, next) {
  res.send('USER');
});

如果需要在中間件棧中跳過剩余中間件,調用 next('route') 方法將控制權交給下一個路由。

// 一個中間件棧,處理指向 /user/:id 的 GET 請求
app.get('/user/:id', function (req, res, next) {
  // 如果 user id 為 0, 跳到下一個路由
  if (req.params.id == 0) next('route');
  // 否則將控制權交給棧中下一個中間件
  else next(); //
}, function (req, res, next) {
  // 渲染常規頁面
  res.render('regular');
});

// 處理 /user/:id, 渲染一個特殊頁面
app.get('/user/:id', function (req, res, next) {
  res.render('special');
});

路由級中間件

var app = express();
var router = express.Router();

// 沒有掛載路徑的中間件,通過該路由的每個請求都會執行該中間件
router.use(function (req, res, next) {
  console.log('Time:', Date.now());
  next();
});

// 一個中間件棧,顯示任何指向 /user/:id 的 HTTP 請求的信息
router.use('/user/:id', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
}, function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

// 一個中間件棧,處理指向 /user/:id 的 GET 請求
router.get('/user/:id', function (req, res, next) {
  // 如果 user id 為 0, 跳到下一個路由
  if (req.params.id == 0) next('route');
  // 負責將控制權交給棧中下一個中間件
  else next(); //
}, function (req, res, next) {
  // 渲染常規頁面
  res.render('regular');
});

// 處理 /user/:id, 渲染一個特殊頁面
router.get('/user/:id', function (req, res, next) {
  console.log(req.params.id);
  res.render('special');
});

// 將路由掛載至應用
app.use('/', router);

錯誤處理中間件

錯誤處理中間件有 4 個參數,定義錯誤處理中間件時必須使用這 4 個參數。即使不需要 next 對象,也必須在簽名中聲明它,否則中間件會被識別為一個常規中間件,不能處理錯誤。
錯誤處理中間件和其他中間件定義類似,只是要使用 4 個參數,而不是 3 個,其簽名如下: (err, req, res, next)。

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

處理404

app.use(function(req, res, next) {
  res.status(404).send('Sorry cant find that!');
});

內置中間件

express.static(root, [options])

express.static 是 Express 唯一內置的中間件。它基于 serve-static,負責在 Express 應用中提托管靜態資源。

app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));

帶選項的 官網

var options = {
  dotfiles: 'ignore',
  etag: false,
  extensions: ['htm', 'html'],
  index: false,
  maxAge: '1d',
  redirect: false,
  setHeaders: function (res, path, stat) {
    res.set('x-timestamp', Date.now());
  }
}

app.use(express.static('public', options));

第三方中間件

例如:

//安裝    
npm install cookie-parser


var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');

// 加載用于解析 cookie 的中間件
app.use(cookieParser());

模板引擎

需要在應用中進行如下設置才能讓 Express 渲染模板文件:

views, 放模板文件的目錄,比如: app.set('views', './views')

view engine, 模板引擎,比如: app.set('view engine', 'jade')

然后安裝相應的模板引擎 npm 軟件包。

npm install jade --save
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容