express框架

来源:http://www.cnblogs.com/xiaohuochai/archive/2017/07/16/7189074.html
-Advertisement-
Play Games

[1]概述 [2]入門實例 [3]生成器 [4]HTTP模塊 [5]中間件 [6]托管靜態資源 [7]常用中間件 [8]路由 [9]路由器實例 [10]響應方法 [11]請求方法 [12]APP方法 [13]HTTPS [14]模板引擎 [15]資料庫 [16]上傳文件 [17]開發實例 ...


前面的話

  Express是一個簡潔、靈活的 node.js Web 應用開發框架, 它提供一系列強大的特性,幫助開發者創建各種 Web 和移動設備應用。本文將詳細介紹express框架

 

概述

  官網對Express的描述,它是一個基於 Node.js 平臺,快速、開放、極簡的 web 開發框架。優點是易上手、高性能、擴展性強

  1、易上手:nodejs最初就是為了開發高性能web伺服器而被設計出來的,然而相對底層的API會讓不少新手望而卻步。express對web開發相關的模塊進行了適度的封裝,屏蔽了大量複雜繁瑣的技術細節,讓開發者只需要專註於業務邏輯的開發,極大的降低了入門和學習的成本

  2、高性能:Express僅在web應用相關的nodejs模塊上進行了適度的封裝和擴展,較大程度避免了過度封裝導致的性能損耗

  3、擴展性強:基於中間件的開發模式,使得express應用的擴展、模塊拆分非常簡單,既靈活,擴展性又強

【安裝】

  安裝express前,首先安裝nodejs,接下來為應用創建一個目錄,然後進入此目錄並將其作為當前工作目錄

$ mkdir myapp
$ cd myapp

  通過 npm init 命令為應用創建一個 package.json 文件

$ npm init

  此命令要求輸入幾個參數,例如應用的名稱和版本。 直接按“回車”鍵接受預設設置即可,下麵這個除外:

entry point: (index.js)

  鍵入 app.js 或者所希望的名稱,這是當前應用的入口文件。如果希望採用預設的 index.js 文件名,只需按“回車”鍵即可

  接下來安裝 Express 並將其保存到依賴列表中:

$ npm install express --save

  如果只是臨時安裝 Express,不想將它添加到依賴列表中,只需略去 --save 參數即可:

$ npm install express

 

入門實例

  在項目根目錄下,新建一個啟動文件,假定叫做index.js,新建一個public文件夾,併在public目錄下,新建index.html

var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(8080);

  運行index.js後,訪問http://localhost:8080,它會在瀏覽器中打開public目錄的index.html文件

  當然,也可以在index.js之中,生成動態網頁

// index.js
var express = require('express');
var app = express();
app.get('/', function (req, res) {
  res.send('Hello world!');
});
app.listen(3000);

  運行index.js文件後,會在本機的3000埠啟動一個網站,網頁顯示Hello World

  啟動腳本index.js的app.get方法,用於指定不同的訪問路徑所對應的回調函數,這叫做“路由”(routing)。上面代碼只指定了根目錄的回調函數,因此只有一個路由記錄。實際應用中,可能有多個路由記錄

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

app.get('/', function (req, res) {
  res.send('Hello world!');
});
app.get('/customer', function(req, res){
  res.send('customer page');
});
app.get('/admin', function(req, res){
  res.send('admin page');
});

app.listen(3000);

  這時,最好就把路由放到一個單獨的文件中,比如新建一個routes子目錄

// routes/index.js
module.exports = function (app) {
  app.get('/', function (req, res) {
    res.send('Hello world');
  });
  app.get('/customer', function(req, res){
    res.send('customer page');
  });
  app.get('/admin', function(req, res){
    res.send('admin page');
  });
};

  然後,原來的index.js就變成下麵這樣

// index.js
var express = require('express');
var app = express();
var routes = require('./routes')(app);
app.listen(3000);

 

生成器

  通過應用生成器工具 express 可以快速創建一個應用的骨架

  [註意]一定要使用全局模式安裝express-generator,否則無法使用express命令

$ npm install express-generator -g

  -h 選項可以列出所有可用的命令行選項:

$ express -h
  Usage: express [options] [dir]
  Options:
    -h, --help          output usage information
    -V, --version       output the version number
    -e, --ejs           add ejs engine support (defaults to jade)
        --hbs           add handlebars engine support
    -H, --hogan         add hogan.js engine support
    -c, --css <engine>  add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
        --git           add .gitignore
    -f, --force         force on non-empty directory

  例如,下麵的示例就是在當前工作目錄下創建一個命名為 myapp 的應用

$ express myapp

   create : myapp
   create : myapp/package.json
   create : myapp/app.js
   create : myapp/public
   create : myapp/public/javascripts
   create : myapp/public/images
   create : myapp/routes
   create : myapp/routes/index.js
   create : myapp/routes/users.js
   create : myapp/public/stylesheets
   create : myapp/public/stylesheets/style.css
   create : myapp/views
   create : myapp/views/index.jade
   create : myapp/views/layout.jade
   create : myapp/views/error.jade
   create : myapp/bin
   create : myapp/bin/www

  然後安裝所有依賴包:

$ cd myapp 
$ npm instal

  啟動這個應用(MacOS 或 Linux 平臺):

$ DEBUG=myapp npm start

  Windows 平臺使用如下命令:

> set DEBUG=myapp & npm start

  然後在瀏覽器中打開 http://localhost:3000/ 網址就可以看到這個應用了。i

  通過 Express 應用生成器創建的應用一般都有如下目錄結構:

.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.jade
    ├── index.jade
    └── layout.jade

7 directories, 9 files

 

HTTP模塊

  Express框架建立在node.js內置的http模塊上。http模塊生成伺服器的原始代碼如下

var http = require("http");

var app = http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.end("Hello world!");
});

app.listen(3000, "localhost");

  上面代碼的關鍵是http模塊的createServer方法,表示生成一個HTTP伺服器實例。該方法接受一個回調函數,該回調函數的參數,分別為代表HTTP請求和HTTP回應的request對象和response對象。

  Express框架的核心是對http模塊的再包裝。上面的代碼用Express改寫如下

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

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

app.listen(3000);

  比較兩段代碼,可以看到它們非常接近。原來是用http.createServer方法新建一個app實例,現在則是用Express的構造方法,生成一個Epress實例。兩者的回調函數都是相同的。Express框架等於在http模塊之上,加了一個中間層

 

中間件

【概述】

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

  簡單說,中間件(middleware)就是處理HTTP請求的函數。它最大的特點就是,一個中間件處理完,再傳遞給下一個中間件。App實例在運行過程中,會調用一系列的中間件

  每個中間件可以從App實例,接收三個參數,依次為request對象(代表HTTP請求)、response對象(代表HTTP回應),next回調函數(代表下一個中間件)。每個中間件都可以對HTTP請求(request對象)進行加工,並且決定是否調用next方法,將request對象再傳給下一個中間件

  中間件的功能包括:1、執行任何代碼;2、修改請求和響應對象;3、終結請求-響應迴圈;4、調用堆棧中的下一個中間件

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

  一個不進行任何操作、只傳遞request對象的中間件,就是下麵這樣

function uselessMiddleware(req, res, next) {
  next();
}

  上面代碼的next就是下一個中間件。如果它帶有參數,則代表拋出一個錯誤,參數為錯誤文本

function uselessMiddleware(req, res, next) {
  next('出錯了!');
}

  拋出錯誤以後,後面的中間件將不再執行,直到發現一個錯誤處理函數為止

【分類】

  Express 應用可使用如下幾種中間件:1、應用級中間件;2、路由級中間件;3、錯誤處理中間件;4、內置中間件;5、第三方中間件

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

  2、路由級中間件綁定的對象為 express.Router()

  3、錯誤處理中間件和其他中間件定義類似,只是要使用 4 個參數,而不是 3 個,其簽名如下: (err, req, res, next)

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

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

  5、通過使用第三方中間件從而為 Express 應用增加更多功能。安裝所需功能的 node 模塊,併在應用中載入,可以在應用級載入,也可以在路由級載入。下麵的例子安裝並載入了一個解析 cookie 的中間件: cookie-parser

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

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

【use方法】

  use是express註冊中間件的方法,它返回一個函數。下麵是一個連續調用兩個中間件的例子

var express = require("express");
var http = require("http");

var app = express();

app.use(function(request, response, next) {
  console.log("In comes a " + request.method + " to " + request.url);
  next();
});

app.use(function(request, response) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.end("Hello world!\n");
});

http.createServer(app).listen(1337);

  上面代碼使用app.use方法,註冊了兩個中間件。收到HTTP請求後,先調用第一個中間件,在控制台輸出一行信息,然後通過next方法,將執行權傳給第二個中間件,輸出HTTP回應。由於第二個中間件沒有調用next方法,所以request對象就不再向後傳遞了。

  use方法內部可以對訪問路徑進行判斷,據此實現簡單的路由,根據不同的請求網址,返回不同的網頁內容

var express = require("express");
var http = require("http");

var app = express();

app.use(function(request, response, next) {
  if (request.url == "/") {
    response.writeHead(200, { "Content-Type": "text/plain" });
    response.end("Welcome to the homepage!\n");
  } else {
    next();
  }
});

app.use(function(request, response, next) {
  if (request.url == "/about") {
    response.writeHead(200, { "Content-Type": "text/plain" });
  } else {
    next();
  }
});

app.use(function(request, response) {
  response.writeHead(404, { "Content-Type": "text/plain" });
  response.end("404 error!\n");
});

http.createServer(app).listen(1337);

  上面代碼通過request.url屬性,判斷請求的網址,從而返回不同的內容。註意,app.use方法一共登記了三個中間件,只要請求路徑匹配,就不會將執行權交給下一個中間件。因此,最後一個中間件會返回404錯誤,即前面的中間件都沒匹配請求路徑,找不到所要請求的資源。

  除了在回調函數內部判斷請求的網址,use方法也允許將請求網址寫在第一個參數。這代表,只有請求路徑匹配這個參數,後面的中間件才會生效。無疑,這樣寫更加清晰和方便

app.use('/path', someMiddleware);

  上面代碼表示,只對根目錄的請求,調用某個中間件。

  因此,上面的代碼可以寫成下麵的樣子

var express = require("express");
var http = require("http");

var app = express();

app.use("/home", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.end("Welcome to the homepage!\n");
});

app.use("/about", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.end("Welcome to the about page!\n");
});

app.use(function(request, response) {
  response.writeHead(404, { "Content-Type": "text/plain" });
  response.end("404 error!\n");
});

http.createServer(app).listen(1337);

 

托管靜態資源

  上面介紹了, express.static 是 Express 唯一內置的中間件,負責在 Express 應用中提托管靜態資源,例如圖片、CSS、JavaScript 文件等

express.static(root, [options])

  參數 root 指提供靜態資源的根目錄,可選的 options 參數擁有如下屬性

屬性          類型      預設值     描述
dotfiles      String   “ignore”   是否對外輸出文件名以點開頭的文件。可選值為allow、deny和ignore
etag          Boolean   true     是否啟用 etag 生成
extensions    Array    []       設置文件擴展名備份選項
index          Mixed    “index.html” 發送目錄索引文件,設置為 false 禁用目錄索引。
lastModified    Boolean  true  設置Last-Modified頭為文件在操作系統上的最後修改日期。可選值為truefalse
maxAge          Number   0       以毫秒或者其字元串格式設置 Cache-Control 頭的 max-age 屬性。
redirect        Boolean  true     當路徑為目錄時,重定向至 “/”。
setHeaders      Function          設置 HTTP 頭以提供文件的函數。
var options = {
  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));

  一般地,如果不需要特殊的設置,將靜態資源文件所在的目錄作為參數傳遞給 express.static 中間件就可以提供靜態資源文件的訪問了。例如,假設在 public 目錄放置了圖片、CSS 和 JavaScript 文件

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

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

http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html

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

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

  訪問靜態資源文件時,express.static 中間件會根據目錄添加的順序查找所需的文件。

  如果希望所有通過 express.static 訪問的文件都存放在一個“虛擬(virtual)”目錄(即目錄根本不存在)下麵,可以通過為靜態資源目錄指定一個掛載路徑的方式來實現,如下所示:

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

  現在,可以通過帶有 “/static” 首碼的地址來訪問 public 目錄下麵的文件了

http://localhost:3000/static/images/kitten.jpg
http://localhost:3000/static/css/style.css
http://localhost:3000/static/js/app.js
http://localhost:3000/static/images/bg.png
http://localhost:3000/static/hello.html

 

常用中間件

【cookie-parser()】

  用於解析cookie的中間件,添加中間後,req具備cookies屬性。通過req.cookies.xxx可以訪問cookie的值

$ npm install cookie-parser
var cookieParser = require('cookie-parser')
app.use(cookieParser(secret, options))

  secret 是可選參數,用於對cookie進行簽名 ,通過它可以判斷出客戶是否修改了cookie,這是處於安全考慮,這個參數是任意字元串

  options 可選參數,是一個json對象,可選項包括path、expires、maxAge、domain、secure、httpOnly

var express      = require('express')
var cookieParser = require('cookie-parser')
 
var app = express()
app.use(cookieParser())
 
app.get('/', function(req, res) {
  console.log('Cookies: ', req.cookies)
})
 
app.listen(8080)

【express-session】

  session運行在伺服器端,當客戶端第一次訪問伺服器時,可以將客戶的登錄信息保存。 當客戶訪問其他頁面時,可以判斷客戶的登錄狀態,做出提示,相當於登錄攔截。session可以和Redis或者資料庫等結合做持久化操作,當伺服器掛掉時也不會導致某些客戶信息(購物車)丟失。

  當瀏覽器訪問伺服器併發送第一次請求時,伺服器端會創建一個session對象,生成一個類似於key,value的鍵值對, 然後將key(cookie)返回到瀏覽器(客戶)端,瀏覽器下次再訪問時,攜帶key(cookie),找到對應的session(value)。客戶的信息都保存在session中

$ npm install express-session
var express = require('express')
var session = require('express-session')
var app = express()
app.use(session(options))

  options 常用選項如下:

  name - 預設'connect.sid',可自定義

  store - session 儲存器實例

  secret - 用於對cookie進行簽名 ,通過它可以判斷出客戶是否修改了cookie,這是處於安全考慮,這個參數是任意字元串

  cookie - 對session cookie的設置 。預設值 { path: '/', httpOnly: true, secure: false, maxAge: null }

  genid -  是個函數,調用它來生成一個新的會話ID。 (預設:使用UID2庫)

  rolling -  強制對每個響應的Cookie,重置到期日期。 (預設:false)

  resave - 每一次都重新保存,即使沒修改過(預設:true)

  proxy - ture/false,是否支持trust proxy,,需要設置 app.enable('trust proxy');一般來說,無需設置

  常用方法如下:

  Session.destroy() :刪除session,當檢測到客戶端關閉時調用

  Session.reload() :當session有修改時,刷新session

  Session.regenerate() :將已有session初始化

  Session.save() :保存session

var express = require('express');
var cookieParser = require('cookie-parser');
var session = require('express-session');
 
app.use(cookieParser('sessiontest'));
app.use(session({
 secret: 'sessiontest',//與cookieParser中的一致
 resave: true,
 saveUninitialized:true
}));
//修改router/index.js,第一次請求時保存一條用戶信息。
router.get('/', function(req, res, next) {
 var user={
  name:"Chen-xy",
  age:"22",
  address:"bj"
 }
 req.session.user=user;
 res.render('index', {
  title: 'the test for nodejs session' ,
  name:'sessiontest'
 });
});
//修改router/users.js,判斷用戶是否登陸。
router.get('/', function(req, res, next) {
 if(req.session.user){
  var user=req.session.user;
  var name=user.name;
  res.send('你好'+name+',歡迎來到我的家園。');
 }else{
  res.send('你還沒有登錄,先登錄下再試試!');
 }
});

【serve-favicon】

  設置網站的 favicon圖標

$ npm install serve-favicon
var express = require('express')
var favicon = require('serve-favicon')
var path = require('path')
 
var app = express()
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
 
// Add your routes here, etc. 
 
app.listen(3000)

【body-parser】

  bodyParser用於解析客戶端請求的body中的內容,內部使用JSON編碼處理,url編碼處理以及對於文件的上傳處理

$ npm install body-parser
var bodyParser = require('body-parser')

  1、底層中間件用法:這將攔截和解析所有的請求;也即這種用法是全局的。

var express = require('express')
var bodyParser = require('body-parser')
  
var app = express()
  
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
  
// parse application/json
app.use(bodyParser.json())
  
app.use(function (req, res) {
 res.setHeader('Content-Type', 'text/plain')
 res.write('you posted:\n')
 res.end(JSON.stringify(req.body, null, 2))
})

  use方法調用body-parser實例;且use方法沒有設置路由路徑;這樣的body-parser實例就會對該app所有的請求進行攔截和解析

  2、特定路由下的中間件用法:這種用法是針對特定路由下的特定請求的,只有請求該路由時,中間件才會攔截和解析該請求;也即這種用法是局部的;也是最常用的一個方式

var express = require('express')
var bodyParser = require('body-parser')
  
var app = express()
  
// create application/json parser
var jsonParser = bodyParser.json()
  
// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })
  
// POST /login gets urlencoded bodies
app.post('/login', urlencodedParser, function (req, res) {
 if (!req.body) return res.sendStatus(400)
 res.send('welcome, ' + req.body.username)
})
  
// POST /api/users gets JSON bodies
app.post('/api/users', jsonParser, function (req, res) {
 if (!req.body) return res.sendStatus(400)
 // create user in req.body
})

  express的post(或者get)方法調用body-parser實例;且該方法有設置路由路徑;這樣的body-parser實例就會對該post(或者get)的請求進行攔截和解析

  3、設置Content-Type 屬性;用於修改和設定中間件解析的body內容類型

// parse various different custom JSON types as JSON
app.use(bodyParser.json({ type: 'application/*+json' });
 
// parse some custom thing into a Buffer
app.use(bodyParser.raw({ type: 'application/vnd.custom-type' }));
 
// parse an HTML body into a string
app.use(bodyParser.text({ type: 'text/html' }));

【morgan】

  Mogran是一個node.js關於http請求的express預設的日誌中間件

npm install  morgan

  在basic.js中添加如下代碼

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

app.use(morgan('short'));
app.use(function(req, res, next){
    res.send('ok');
});

app.listen(3000);

  node basic.js運行程式,併在瀏覽器里訪問 http://127.0.0.1:3000 ,列印日誌如下

::1 - GET / HTTP/1.1 200 2 - 3.157 ms
::1 - GET / HTTP/1.1 304 - - 0.784 ms

  morgan支持stream配置項,可以通過它來實現將日誌落地的效果,代碼如下:

var express = require('express');
var app = express();
var morgan = require('morgan');
var fs = require('fs');
var path = require('path');

var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'});

app.use(morgan('short', {stream: accessLogStream}));
app.use(function(req, res, next){
    res.send('ok');
});

app.listen(3000);

  morgan的API非常少,使用頻率最高的就是morgan(),作用是返回一個express日誌中間件

morgan(format, options)

  參數說明如下:

  format:可選,morgan與定義了幾種日誌格式,每種格式都有對應的名稱,比如combined、short等,預設是default

  options:可選,配置項,包含stream(常用)、skip、immediate

  stream:日誌的輸出流配置,預設是process.stdout

  skip:是否跳過日誌記錄

  immediate:布爾值,預設是false。當為true時,一收到請求,就記錄日誌;如果為false,則在請求返回後,再記錄日誌

 

路由

【路由方法】

  針對不同的請求,Express提供了use方法的一些別名,這些別名是和 HTTP 請求對應的路由方法: getpostputheaddeleteoptionstracecopylockmkcolmovepurgepropfindproppatchunlockreportmkactivitycheckoutmergem-searchnotifysubscribeunsubscribepatchsearch 和 connect

  app.all() 是一個特殊的路由方法,沒有任何 HTTP 方法與其對應,它的作用是對於一個路徑上的所有請求載入中間件

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

var express = require("express");
var http = require("http");
var app = express();

app.all("*", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  next();
});

app.get("/", function(request, response) {
  response.end("Welcome to the homepage!");
});

app.get("/about", function(request, response) {
  response.end("Welcome to the about page!");
});

app.get("*", function(request, response) {
  response.end("404!");
});

http.createServer(app).listen(1337);

  上面代碼的all方法表示,所有請求都必須通過該中間件,參數中的“*”表示對所有路徑有效。get方法則是只有GET動詞的HTTP請求通過該中間件,它的第一個參數是請求的路徑。由於get方法的回調函數沒有調用next方法,所以只要有一個中間件被調用了,後面的中間件就不會再被調用了

【路由路徑】

  路由方法的第一個參數,都是請求的路徑,稱為路由路徑,它可以是字元串、字元串模式或者正則表達式

  1、字元串匹配

// 匹配 /about 路徑的請求
app.get('/about', function (req, res) {
  res.send('about');
});

  2、字元串模式匹配

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

  3、正則表達式匹配

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

【路由句柄】

  可以為請求處理提供多個回調函數,其行為類似中間件。唯一的區別是這些回調函數可能調用 next('route') 方法而略過其他路由回調函數。可以利用該機製為路由定義前提條件,如果在現有路徑上繼續執行沒有意義,則可將控制權交給剩下的路徑

  路由句柄有多種形式,可以是一個函數、一個函數數組,或者是兩者混合

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

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

  2、使用多個回調函數處理路由

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

  3、使用回調函數數組處理路由

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

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

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

【鏈式路由句柄】

  可使用 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 4.0開始,路由器功能成了一個單獨的組件Express.Router。它好像小型的express應用程式一樣,有自己的use、get、param和route方法

  可使用 express.Router 類創建模塊化、可掛載的路由句柄。Router 實例是一個完整的中間件和路由系統,因此常稱其為一個 “mini-app”

【基本用法】

  首先,Express.Router是一個構造函數,調用後返回一個路由器實例。然後,使用該實例的HTTP動詞方法,為不同的訪問路徑,指定回調函數;最後,掛載到某個路徑

var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
  res.send('首頁');
});
router.get('/about', function(req, res) {
  res.send('關於');
});
app.use('/', router);

  上面代碼先定義了兩個訪問路徑,然後將它們掛載到根目錄。如果最後一行改為app.use(‘/app’, router),則相當於為/app/app/about這兩個路徑,指定了回調函數。

  這種路由器可以自由掛載的做法,為程式帶來了更大的靈活性,既可以定義多個路由器實例,也可以為將同一個路由器實例掛載到多個路徑

【router.route方法】

  router實例對象的route方法,可以接受訪問路徑作為參數

var express = require('express');
var router = express.Router();
router.route('/api')
    .post(function(req, res) {
        // ...
    })
    .get(function(req, res) {
        Bear.find(function(err, bears) {
            if (err) res.send(err);
            res.json(bears);
        });
    });
app.use('/', router);

【router中間件】

  use方法為router對象指定中間件,在數據正式發給用戶之前,對數據進行處理。下麵是一個中間件的例子

router.use(function(req, res, next) {
    console.log(req.method, req.url);
    next();    
});

  上面代碼中,回調函數的next參數,表示接受其他中間件的調用。函數體中的next(),表示將數據傳遞給下一個中間件

  [註意]中間件放置順序很重要,等同於執行順序。而且,中間件必須放在HTTP動詞方法之前,否則不會執行

【對路徑參數的處理】

  router對象的param方法用於路徑參數的處理

router.param('name', function(req, res, next, name) {
    // 對name進行驗證或其他處理……
    console.log(name);
    req.name = name;
    next();    
});
router.get('/hello/:name', function(req, res) {
    res.send('hello ' + req.name + '!');
});

  上面代碼中,get方法為訪問路徑指定了name參數,param方法則是對name參數進行處理

  [註意]param方法必須放在HTTP動詞方法之前

【實例】

  下麵的實常式序創建了一個路由模塊,並載入了一個中間件,定義了一些路由,並且將它們掛載至應用路徑上

  在 app 目錄下創建名為 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 中間件

 

響應方法

  response對象包含以下9個方法,response對象的方法向客戶端返迴響應,終結請求響應的迴圈。如果在路由句柄中一個方法也不調用,來自客戶端的請求會一直掛起

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

  1、response.download方法

//下載路徑為'/report-12345.pdf'的文件
res.download('/report-12345.pdf');

//下載路徑為'/report-12345.pdf'的文件,並將文件命名為 'report.pdf'
res.download('/report-12345.pdf', 'report.pdf');

//下載路徑為'/report-12345.pdf'的文件,將文件命名為 'report.pdf',並且回調
res.download('/report-12345.pdf', 'report.pdf', function(err){
  if (err) {
  } else {
  }
});

  2、response.end方法

//終結響應處理流程
res.end();
//設置響應碼為404,並終結響應處理流程
res.status(404).end();

  3、response.json方法

res.json(null)
res.json({ user: 'tobi' })
res.status(500).json({ error: 'message' })

  4、response.jsonp方法

res.jsonp(null)
res.jsonp({ user: 'tobi' })
res.status(500).jsonp({ error: 'message' })

  5、response.redirect方法

res.redirect('/foo/bar');
res.redirect('http://example.com');
res.redirect(301, 'http://example.com');
res.redirect('../login');

  6、response.render方法

res.render('index');
res.render('index', function(err, html) {
  res.send(html);
});
res.render('user', { name: 'Tobi' }, function(err, html) {
  // ...
});

  7、response.send方法

res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('<p>some html</p>');
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });

  8、response.sendFile方法

response.sendFile("/path/to/anime.mp4");

  9、response.sendStatus方法

res.sendStatus(200); // 'OK'
res.sendStatus(403); // 'Forbidden'
res.sendStatus(404); // 'Not Found'
res.sendStatus(500); // 'Internal Server Error'

 

請求方法

【req.params】

// GET /user/tj
req.params.name
// => "tj"

// GET /file/javascripts/jquery.js
req.params[0]
// => "javascripts/jquery.js"

【req.query】

// GET /search?q=tobi+ferret
req.query.q
// => "tobi ferret"

// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
req.query.order
// => "desc"

req.query.shoe.color
// => "blue"

req.query.shoe.type
// => "converse"

【req.body】

// POST user[name]=tobi&user[email][email protected]
req.body.user.name
// => "tobi"

req.body.user.email
// => "[email protected]"

// POST { "name": "tobi" }
req.body.name
// => "tobi"

【req.param(name)】

// ?name=tobi
req.param('name')
// => "tobi"

// POST name=tobi
req.param('name')
//	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天在切圖的時候,碰到一個相容性的問題,很幸運最後通過張金鑫老師的文章解決了這個問題!但在閱讀張老師文章的時候,我有個地方不明白,在網上查了下也沒找到我想要的答案,後來自己想了半天好像是這麼回事,現在我把我的想法寫出來,如果有不對的地方,大家一定要指出哦。 如圖(事例1): 這是張老師文章中的一段事 ...
  • 一 概述 1.什麼是HTML? HyperText Markup Language,超文本標記語言,客戶端技術的技術,負責頁面展示。 2.HTML的特點 標簽不區分大小寫。 3.請求地址 HTML是客戶端技術的基礎,HTML運行在客戶端,面向整個互聯網,為了能夠保證正確地定位資源,在書寫請求地址時, ...
  • 2016年10月我參加了在北京舉行的DevDays Asia 2016 - Office 365應用開發”48小時黑客馬拉松“,我開發的一個Word Add-In Demo——WordTemplateHelper獲得了二等獎。在會場有幸結識了陳希章老師,在與陳老師的交流中受益良多,得知陳老師在準備一 ...
  • yahoo軍規一共分7類共35條: 1.儘量減少HTTP請求數 分類: 內容 80%的終端用戶響應時間都花在了前端上,其中大部分時間都在下載頁面上的各種組件:圖片,樣式表,腳本,Flash等等。減少組件數必然能夠減少頁面提交的HTTP請求數。這是讓頁面更快的關鍵。 減少頁面組件數的一種方式是簡化頁面 ...
  • 具體代碼如下: <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>*{margin:0;padding:0;font-size:14px;-webkit-user-sele ...
  • 今天看的《JavaScript設計模式》-作者:張容銘。主要看了js繼承。下麵我將看的,以及代碼貼出來,跟大家一起學習,分享。共同進步。 先來個簡單是 單繼承 多繼承 類繼承 是通過子類的原型prototype對父類實例化來實現的 缺點:父類中的共有屬性如果是引用類型就會在子類的所有實例中共擁有,一 ...
  • JavaWeb01_html basic html操作思想 使用標簽把要操作的數據包起來,通過修改標簽的屬性值,來實現標簽內數據樣式的變化 font標簽 屬性:size取值範圍1-7 color:英文單詞,十六進位數 #ffffff 標題標簽 <h1> </h1> ... <h6> </h6> 從h ...
  • 綱要 =============================== 計劃佈局,劃分整體結構 內容區域,從整體到局部,局部中的通用部分,根據上下文應用樣式 公共頭部(public header)、尾部(public footer) 公共容器(public container/inner center ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...