1. 程式人生 > >【重拾】深入理解express框架

【重拾】深入理解express框架

寫在前面

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

Express 框架核心特性:

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

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

底層HTTP伺服器

學習nodeJS基礎的時候我們經常要用到 http

這個核心模組,它以極其簡潔JavaScript程式碼 搭建出本地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 獲得「請求主體」/ 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型別

路由

最原始的路由:

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.

參考資料