Express官網說:Express是基于 Node.js 平臺的 web 開發框架。這句話包含了兩個部分內容,一是Express基于Node.js平臺,二是Express是一個web開發框架。說的更直白一些意思就是,使用Express以后,底層工作的還是Node.js;即使不用Express,也完全可以搞web開發,用了Express只是會讓web開發變得更簡單一些。Node.js是從0到1,Experss是從1到10。
不使用任何開發框架,只用Node.js如何實現一個web服務
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Node.js自帶的http模塊做了很多工作,和操作系統打交道,監聽3000端口,每當有http請求到達3000端口時,構造request和response對象,調用創建server對象時傳給 http.createServer
的回調函數并將request和response分別用參數req和res傳入。在回調函數中,在req中取得http請求相關輸入信息,經過處理后,調用res的方法將結果輸出。
使用Express以后的情形
使用Express實現的web服務,代碼和上面的純Node.js版差不多:
const express = require('express')
const app = express()
const hostname = '127.0.0.1'
const port = 3000
app.use(function (req, res, next) {
res.statusCode = 200
res.setHeader('Content-Type', 'text/plain')
res.end('Hello World!')
})
app.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
})
除了最開始引用的包不同以外,唯一的區別就是請求處理回調函數的使用方式,Node.js用http.createServer
,Experss用app.use
。
Express版的回調函數中,req和res其實就是Node.js傳入的,Node.js版req和res對象的方法、屬性在Express中都能用,Express還額外為req和res對象添加了一些方法,更加簡化web開發。
最后的listen方法參數也完全一樣,因為Express的app.listen方法只是簡單地把參數全部傳給Node.js的server.listen方法。
Express的核心,中間件
從上面的兩個Hello World示例程序回到現實世界,現實中我們總是要對不同的url使用單獨的處理邏輯,如果不用框架而只使用純Node.js的方式,無疑會非常復雜低效,代碼大概就會像這樣:
const server = http.createServer((req, res) => {
if(req.url == '/') {
//處理/
} else if (req.url === '/products') {
//處理/products
} else if (...) {}
//更多分支...
});
Express解決這個問題的辦法,是使用中間件。一個用Express開發的web服務,本質上就是對一系列中間件的順序調用。中間件非常簡單,就是一些函數,這些函數可以執行任何代碼,只需符合簡單的約定即可:
接受3個參數(錯誤處理中間件是4個參數,不過這個小差異不影響對Experss中間件本質的理解),req,res,next。req是請求對象,可以從這個對象中讀取所有關于http請求的信息,如header,querystring,body等;res是響應對象,可以通過調用res的方法將處理結果輸出到http response;next是一個函數,如果當前中間件沒有終結請求-響應循環,則必須調用 next() 方法將控制權交給下一個中間件,否則請求就會掛起。
只要符合這個約定的函數,都可以作為中間件,“掛載(mount)”到整個web應用程序或某一個特定的url和method上,Express在處理一個http 請求時,會從所有已掛載的中間件中,根據http 請求的輸入信息(url、method)找出所有符合條件的中間件并按順序執行,先掛載的先執行。