1. 程式人生 > >Node中的Connect——常用中介軟體

Node中的Connect——常用中介軟體

接下來介紹一個Connect內建的一些中介軟體:

static中介軟體

  1.掛載
  static允許將任意一個URL匹配到檔案系統中任意一個目錄。如:將/my-images URL和名為/images的目錄對應起來,可以以如下方式進行掛載:

server.use('/my-images', connect.static('/path/to/images'));

  2. maxAge
  static中介軟體接收一個名為maxAge的選項,這個選項代表一個資源在客戶端快取的時間。對於一些不經常改動的資源來說,我們可以進行快取,瀏覽器就無需每次都去請求它了。

server.use
('/js', connect.static('/path/to/bundles', {maxAge: 1000000000000}));

  比如,一種Web應用常見的實踐方式就是將所有的客戶端JavaScript檔案都合併到一個檔案中,並在檔名中加上修訂號。這個時候,就可以設定maxAge選項,讓其永遠快取起來。如上述程式碼。
  3. hidden
  static接收的另一引數hidden。當hidden值為true時,Connect會託管那些檔名以點(.)開始的在UNIX檔案系統中被認為是隱藏的檔案:

server.use(connect.static('/path/to/resources', {hidden: true
}));

query中介軟體

  使用query中介軟體,能夠通過req.query物件自動獲取URL中的查詢字串。如:我們請求url /blog?page=5時,我們獲取資料查詢字串 page=5,可以這麼使用(req.url變數中儲存著URL的值,即 /blog?page=5):

server.use(connect.query);
server.use(function(req, res) {
    // req.query.page == "5"
});

logger中介軟體

  logger中介軟體將傳送進來的請求資訊和傳送出去的響應資訊列印在終端。
  它提供了以下四種日誌格式:
  - default
  - dev
  - short
  - tiny
  如:使用dev日誌格式,可以通過如下初始化logger中間的方式:

server.use(connect.logger('dev'));

  dev是一種精準簡短的日誌格式,能夠提供行為以及效能方面的資訊,方便測試Web應用。
  logger中間還允許自定義日誌輸出格式,還能通過動態的req和res來記錄頭資訊。
  下面是完整的可用token:
  - :req[header](如:req[accept])
  - :res[header](如:res[content-length])
  - :http-version
  - :response-time
  - :remote-addr
  - :date
  - :method
  - :url
  - :referrer
  - :user-agent
  - :status
  使用如下:

server.use(connect.logger(':method :remote-addr'));
server.use(connect.logger('type is :res[content-type], length is '
    + ':res[content-length] and it took :response-time ms.'));

  logger還能夠自定義token。如,要給請求Content-Type定義一個簡寫的:type token,可以採用如下方式:

connect.logger.token('type', function(req, res) {
    return req.headers['content-type'];
});

body parser中介軟體

  1.接收POST資料
  使用body parse中介軟體可以接收POST請求的資料,並將資料儲存到req.body中。如:

server.use(connect.bodyParser());
server.use(function(req, res) {
    // req.body.myinput
});

  2.處理上傳
  bodyParser另一功能就是使用formidable模組,它可以讓你處理使用者上傳的檔案。如:

var server = connect(
    connect.bodyParser(),
    connect.static('static')
);
server.use(function(req, res, next) {
    if('POST' == req.method && req.body.file) {
        console.log(req.body.file);
        fs.readFile(req.body.file.path, 'utf8', function(err, data) {
            if(err) {
                res.writeHead(500);
                res.end('Error!');
                return;
            }

            res.writeHead(200, {'Content-Type': 'text/html'});
            res.end([
                '<h3>File: ' + req.body.file.name + '</h3>',
                '<h4>Type: ' + req.body.file.type + '</h4>',
                '<h4>Contents:</h4><pre>' + data + '</pre>'
            ].join(''));
        });
    } else {
        next();
    }
});

  3.多檔案上傳
  在input的name屬性上加上[],即

<input type="file" name="files[]"/>
<input type="file" name="files[]"/>

  這個時候為多檔案上傳,這時req.body.files就包含了一個數組。

  當瀏覽器傳送cookie資料時,會將其寫到cookie頭資訊中。其資料格式和URL中的查詢字串類似。如:

GET /detail HTTP/1.1
Host: 127.0.0.1
Cookie: key1=value1; key2=value2
Accept: */*

  使用cookieParser中介軟體就可以通過req.cookies物件輕鬆訪問到這些cookie資料:

server.use(connect.cookieParser());
server.use(function(req, res, next) {
    // req.cookies.key1 = "value1";
    // req.cookies.key2 = "value2";
});

會話(session)

  在絕大多數Web應用中,多個請求間共享“使用者會話”的概念是非常必要的。它主要通過在瀏覽器中設定cookie來實現,該cookie資訊會在隨後所有的請求頭資訊中被帶回到伺服器中。
  使用者登入的案例:

var connect = require('connect'),
    users = require('./users'); // 這裡直接require了JSON檔案,不需要使用module.exports對資料進行暴露

var server = connect(
    connect.logger('dev'),
    connect.bodyParser(),
    connect.cookieParser(),
    // 出於安全考慮,在初始化session中介軟體的時候需要提供secret選項
    connect.session({secret: 'my app secret'}),
    function(req, res, next) {
        if('/' == req.url && req.session.logged_in) {
            res.writeHead(200, {'Content-Type': 'text/html'});
            res.end('Welcome back, <b>' + req.session.name + '</b>.'
                + '<a href="/logout">Logout</a>');
        } else {
            next();
        }
    },
    function(req, res, next) {
        if('/' == req.url && 'GET' == req.method) {
            res.writeHead(200, {'Content-Type': 'text/html'});
            res.end([
                '<form action="/login" method="POST">',
                '<fieldset>',
                '<legend>Please log in</legend>',
                '<p>User: <input type="text" name="user"></p>',
                '<p>Password: <input type="password" name="password"></p>',
                '<button>Submit</button>',
                '</fieldset>',
                '</form>'
                ].join(''));
        } else {
            next();
        }
    },
    function(req, res, next) {
        if('/login' == req.url && 'POST' == req.method) {
            res.writeHead(200);
            if(!users[req.body.user] || req.body.password != users[req.body.user].password) {
                res.end('Bad username/password');
            } else {
                req.session.logged_in = true;
                req.session.name = users[req.body.user].name;
                res.end('Authenticated!');
            }
        } else {
            next();
        }
    },
    function(req, res, next) {
        if('/logout' == req.url) {
            req.session.logged_in = false;
            res.writeHead(200);
            res.end('Logged out!');
        } else {
            next();
        }
    }
);

server.listen(3000);

  其中users.json檔案內容如下:

{
    "DreamBoy": {
        "password": "123",
        "name": "夢小白"
    }
}

  為了讓session能夠在生產環境中也正常工作,我們需要通過Redis來實現一個持久化。

Redis session

  當我們登入成功後,重啟node伺服器,然後重新整理瀏覽器,會發現需要重新登入,也就是說session失效或或者說不見了。
  原因在於session預設儲存在記憶體中。這意味著session資料儲存在記憶體中時,當程序退出後,session資料自然也就丟失了。
  生產環境中,需要使用一種當應用重啟後,還能夠將session資訊持久化儲存下來的機制,如Redis。
  Redis是一個既小又快的資料庫,有一個connect-redis模組使用Redis來持久化session資料,這樣就讓session駐紮到了Node程序之外。
  使用如下(必須要安裝好Redis):

var connect = require('connect'),
    RedisStore = require('connect-redis')(connect);

  使用中介軟體:

server.use(connect.session({store: new RedisStore, secret: 'my secret'}));

methodOverrid中介軟體

basicAuth中介軟體

注:暫不說明。

總結

  1. 中介軟體是序列執行的。
  2. 使用中介軟體的好處:程式碼能以此為構建單元進行組織,並且能夠獲得高複用性。
  3. Connect是實現了中介軟體這一思路的模組,它為構建更具表達力的中介軟體提供了基礎架構。