【重拾】深入理解express框架
寫在前面
Express 是一個簡潔而靈活的 node.js Web應用框架, 提供了一系列強大特性幫助你建立各種 Web 應用,和豐富的 HTTP 工具。使用 Express 可以快速地搭建一個完整功能的網站。
Express 框架核心特性:
- 可以設定中介軟體來響應 HTTP 請求。
- 定義了路由表用於執行不同的 HTTP 請求動作。
- 可以通過向模板傳遞引數來動態渲染 HTML頁面。
今天不介紹基本用法,如何用它搭建nodeJS中間層在我前面的文章裡有比較詳細的介紹,而這次主要是深入研究它的內部實現原理。
底層HTTP伺服器
學習nodeJS基礎的時候我們經常要用到 http
// 引入所需模組
var http = require("http");
// 建立伺服器
var app = http.createServer(function(request, response) {
response.writeHead(200, {
"Content-Type": "text/plain"
});
response.end("Hello world!\n");
});
// 啟動伺服器
app.listen(1337, "localhost");
console.log("Server running at http://localhost:1337/" );
解析: 第一行使用
require
函式引入Node內建模組http
。然後存入名為http
的變數中。然後我們使用http.createServer()
將伺服器儲存至 app 變數。它將一個函式作為引數監聽請求。稍後將會詳細介紹它。最後我們要做的就是告訴伺服器監聽來自1337埠的請求,之後輸出結果。然後一切完成。
中介軟體
通過中介軟體,搭建本地伺服器的過程變得簡單,比如最簡單的connect
// 引入所需模組
var connect = require("connect");
var http = require("http");
// 建立app
var app = connect();
// 新增中介軟體
app.use(function(request, response) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello world!\n");
});
// 啟動應用
http.createServer(app).listen(1337);
express 4.x 已經把connect中介軟體封裝的express模組裡。因此我們不需要依賴connect模組:
var express = require('express');
var app = express();
var server = app.listen(8081, function () {
console.log("Server running at http://localhost:1337/")
});
什麼是中介軟體
一個最基本的中介軟體結構如下:
function myFunMiddleware(request, response, next) {
// 對request和response作出相應操作
// 操作完畢後返回next()即可轉入下個中介軟體
next();
}
當我們啟動一個伺服器,函式開始從頂部一直往下執行。還是還來個能跑的程式
var connect = require("connect");
var http = require("http");
var app = connect();
app.use(connect.logger());
// Homepage
app.use(function(request, response, next) {
if (request.url == "/") {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Welcome to the homepage!\n");
// The middleware stops here.
} else {
next();
}
});
// About page
app.use(function(request, response, next) {
if (request.url == "/about") {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Welcome to the about page!\n");
// The middleware stops here.
} else {
next();
}
});
// 404'd!
app.use(function(request, response) {
response.writeHead(404, { "Content-Type": "text/plain" });
response.end("404 error!\n");
});
http.createServer(app).listen(1337);
是的,這樣的過程略顯繁瑣,因此express
把connect封裝到了自己模組裡,用express實現上面的過程簡單了不少(往下看) 。
請求和響應
Request 物件
request 物件表示 HTTP 請求,包含了請求查詢字串,引數,內容,HTTP 頭部等屬性。常用屬性和方法有16項
req.app
當callback為外部檔案時,用req.app訪問express的例項。req.baseUrl
獲取路由當前安裝的URL路徑req.body
/req.cookies
獲得「請求主體」/ Cookiesreq.fresh
/req.stale
判斷請求是否還「新鮮」req.hostname
/req.ip
獲取主機名和IP地址req.originalUrl
獲取原始請求URLreq.params
獲取路由的parametersreq.path
獲取請求路徑req.protocol
獲取協議型別req.query
獲取URL的查詢引數串req.route
獲取當前匹配的路由req.subdomains
獲取子域名req.accpets()
檢查請求的Accept頭的請求型別req.acceptsCharsets
/req.acceptsEncodings
/req.acceptsLanguages
req.get()
獲取指定的HTTP請求頭req.is()
判斷請求頭Content-Type的MIME型別
Response 物件
response 物件表示 HTTP 響應,即在接收到請求時向客戶端傳送的 HTTP 響應資料。常見屬性有以下17項。
res.app
同req.app一樣res.append()
追加指定HTTP頭res.set()
在res.append()
後將重置之前設定的頭res.cookie(name,value [,option])
設定Cookieopition
domain
/expires
/httpOnly
/maxAge
/path
/secure
/signed
res.clearCookie()
清除Cookieres.download()
傳送指定路徑的檔案res.get()
返回指定的HTTP頭res.json()
傳送JSON響應res.jsonp()
傳送JSONP響應res.location()
只設置響應的Location HTTP頭,不設定狀態碼或者close responseres.redirect()
設定響應的Location HTTP頭,並且設定狀態碼302res.send()
傳送HTTP響應res.sendFile(path [,options] [,fn])
傳送指定路徑的檔案 -會自動根據檔案extension設定Content-Typeres.set()
設定HTTP頭,傳入object可以一次設定多個頭res.status()
設定HTTP狀態碼res.type()
設定Content-Type的MIME型別
路由
最原始的路由:
var http = require("http");
http.createServer(function(req, res) {
// Homepage
if(req.url == "/") {
res.writeHead(200, { "Content-Type": "text/html" });
res.end("Welcome to the homepage!");
}
// About page
else if (req.url == "/about") {
res.writeHead(200, { "Content-Type": "text/html" });
res.end("Welcome to the about page!");
}
// 404'd!
else {
res.writeHead(404, { "Content-Type": "text/plain" });
res.end("404 error! File not found.");
}
}).listen(1337, "localhost");
express封裝的路由:
var express = require('express');
var app = express();
// 主頁輸出 "Hello World"
app.get('/', function (req, res) {
console.log("主頁 GET 請求");
res.send('Hello GET');
})
// POST 請求
app.post('/', function (req, res) {
console.log("主頁 POST 請求");
res.send('Hello POST');
})
// /del_user 頁面響應
app.delete('/del_user', function (req, res) {
console.log("/del_user 響應 DELETE 請求");
res.send('刪除頁面');
})
// /list_user 頁面 GET 請求
app.get('/list_user', function (req, res) {
console.log("/list_user GET 請求");
res.send('使用者列表頁面');
})
// 對頁面 abcd, abxcd, ab123cd, 等響應 GET 請求
app.get('/ab*cd', function(req, res) {
console.log("/ab*cd GET 請求");
res.send('正則匹配');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("應用例項,訪問地址為 http://%s:%s", host, port)
});
檢視
express結合前端模板引擎可以在服務端實現檢視的渲染,這裡還是以 jade模板引擎為例:
// 啟動Express
var express = require("express");
var app = express();
// 設定view目錄
app.set("views", __dirname + "/views");
// 設定模板引擎
app.set("view engine", "jade");
開頭部分的程式碼和前面基本一樣。之後我們指定檢視檔案所在目錄。然後告訴Express我們要使用 Jade作為模板引擎。
接下來 我們建立一個名為 index.jade 的檔案並把它放入 views 目錄。程式碼如下:
doctype 5
html
body
h1 Hello, world!
p= message
我們需要從Express中渲染這個檢視。程式碼如下:
app.get("/", function(request, response) {
response.render("index", { message: "I love anime" });
});
Express為 response 物件添加了一個 render 方法。這個方法可以處理很多事情,但最主要的還是載入模板引擎和對應的檢視檔案,之後渲染成普通的HTML文件,例如這裡的 index.jade.