1. 程式人生 > >深入理解express框架

深入理解express框架

寫在前面

Express 是一個簡潔而靈活的 node.js Web應用框架, 提供了一系列強大特性幫助你建立各種 Web 應用,和豐富的 HTTP 工具。使用 Express 可以快速地搭建一個完整功能的網站。http://jafeney.com/2016/01/10/2016-01-10-express/

Express 框架核心特性:

  • 可以設定中介軟體來響應 HTTP 請求。
  • 定義了路由表用於執行不同的 HTTP 請求動作。
  • 可以通過向模板傳遞引數來動態渲染 HTML頁面。

今天不介紹基本用法,如何用它搭建nodeJS中間層在我前面的文章裡有比較詳細的介紹,而這次主要是深入研究它的內部實現原理。

底層HTTP伺服器

學習nodeJS基礎的時候我們經常要用到 http 這個核心模組,它以極其簡潔JavaScript程式碼 搭建出本地http服務.

1234567891011121314 // 引入所需模組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

123456789101112131415 // 引入所需模組var connect = require("connect");var http = require("http");// 建立appvar 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模組:

123456 var express = require('express');var app = express();var server = app.listen(8081, function () { console.log("Server running at http://localhost:1337/")});

什麼是中介軟體

一個最基本的中介軟體結構如下:

12345 function myFunMiddleware(request, response, next) { // 對request和response作出相應操作 // 操作完畢後返回next()即可轉入下個中介軟體 next();}

當我們啟動一個伺服器,函式開始從頂部一直往下執行。還是還來個能跑的程式

12345678910111213141516171819202122232425262728293031323334353637 var connect = require("connect");var http = require("http");var app = connect();app.use(connect.logger());// Homepageapp.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 pageapp.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 獲得「請求主體」/ Cookies
  • req.fresh / req.stale 判斷請求是否還「新鮮」
  • req.hostname / req.ip 獲取主機名和IP地址
  • req.originalUrl 獲取原始請求URL
  • req.params 獲取路由的parameters
  • req.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]) 設定Cookie
  • opition domain / expires / httpOnly / maxAge / path / secure / signed
  • res.clearCookie() 清除Cookie
  • res.download() 傳送指定路徑的檔案
  • res.get() 返回指定的HTTP頭
  • res.json() 傳送JSON響應
  • res.jsonp() 傳送JSONP響應
  • res.location() 只設置響應的Location HTTP頭,不設定狀態碼或者close response
  • res.redirect() 設定響應的Location HTTP頭,並且設定狀態碼302
  • res.send() 傳送HTTP響應
  • res.sendFile(path [,options] [,fn]) 傳送指定路徑的檔案 -會自動根據檔案extension設定Content-Type
  • res.set() 設定HTTP頭,傳入object可以一次設定多個頭
  • res.status() 設定HTTP狀態碼
  • res.type() 設定Content-Type的MIME型別

路由

最原始的路由:

12345678910111213141516171819202122 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封裝的路由:

1234567891011121314151617181920212223242526272829303132333435363738 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模板引擎為例:

123456789 // 啟動Expressvar express = require("express");var app = express();// 設定view目錄app.set("views", __dirname + "/views");// 設定模板引擎app.set("view engine", "jade");

開頭部分的程式碼和前面基本一樣。之後我們指定檢視檔案所在目錄。然後告訴Express我們要使用 Jade作為模板引擎。

接下來 我們建立一個名為 index.jade 的檔案並把它放入 views 目錄。程式碼如下:

12345 doctype 5html body h1 Hello, world! p= message

我們需要從Express中渲染這個檢視。程式碼如下:

123 app.get("/", function(request, response) { response.render("index", { message: "I love anime" }); });

Express為 response 物件添加了一個 render 方法。這個方法可以處理很多事情,但最主要的還是載入模板引擎和對應的檢視檔案,之後渲染成普通的HTML文件,例如這裡的 index.jade.

參考資料