iT邦幫忙

DAY 8
6

node.js伺服器實戰系列 第 8

node.js伺服器實戰(8) - 目錄的預設index檔

通常在使用網站時,通常只會輸入目錄,而不是index.html,所以要讓伺服器可以支援目錄預設的index檔,功能才比較完整。
在Apache httpd中的做法

在Apache中,要設定目錄預設的index檔,通常是:

 <IfModule dir_module>
     DirectoryIndex index.php index.html index.htm
 </IfModule>

設定好了以後,如果客戶端請求的資源是一個目錄,他會依照上面的順序看看有沒有這些檔案,如果不存在,又不允許做目錄瀏覽,就會出現Permission denied.的錯誤訊息。為了簡化問題,我會傾向如果沒有這些檔案存在,就直接出現Permission denied.。(通常也會關掉以確保安全)

在node.js實做

簡單的邏輯,是先用fs.stat()判斷request的資源是否為目錄,如果是目錄,就依照設定的index檔順序尋找,找到了就response這個檔案的內容。

如果不是目錄,就利用fs.readFile尋找檔案,找到檔案就reponse這個檔案的內容。

fs.stat()以及fs.readFile()都是使用非同步的方式操作,需要傳一個callback函數給他。另外,為了顧及可能的狀況,所以程式膨脹許多:

 var http = require('http'),
     fs = require('fs'),
     url = require('url'),
     mime = require('../deps/mime'),
     path = require('path'),
     evolve = function(conf) {//利用一個constructor包裝
         var server = http.createServer(function(request, response) {
             var urlObj = url.parse(request.url);
             var respath = path.join(conf.basedir, urlObj.pathname);
             console.log('request: ' + respath);
             fs.stat(respath, function(err, stats) {//請求資源路徑的stats
                 if(err) {
                     console.log(respath + ' not exists.');
                     response.writeHead(404, '');
                     response.end();
                 } else {
                     if(stats.isDirectory()) {//如果是目錄,則處理index檔
                         var ic=0;
                         fs.readFile(path.join(respath, conf.dirindex[ic]), function dih(err, data) {
                             ic++;
                             if(err) {
                                 if(ic<conf.dirindex.length) {
                                     fs.readFile(path.join(respath, conf.dirindex[ic]), dih);
                                 } else {
                                     console.log(path.join(respath, conf.dirindex[ic-1]) + ' not exists.');
                                     response.writeHead(404, '');
                                     response.end();
                                 }
                             } else {
                                 console.log(path.join(respath, conf.dirindex[ic-1]) + ' exists.');
                                 response.writeHead(200, {
                                     "Content-Type": mime.lookup(path.join(respath, conf.dirindex[ic-1])),
                                     "Content-Length": data.length
                                 });
                                 response.end(data);
                             }
                         });
                     } else {//不是目錄,開始處理檔案
                         fs.readFile(respath, function(err, data) {
                             if(err) {
                                 console.log(respath + ' not exists.');
                                 response.writeHead(404, '');
                                 response.end();
                             } else {
                                 console.log(respath + ' exists.');
                                 response.writeHead(200, {
                                     "Content-Type": mime.lookup(respath), 
                                     "Content-Length": data.length
                                 });
                                 response.end(data);
                             }
                         });
                     }
                 }
             });
         });
         this.listen = function(port, addr) {//wrap函數,把listen轉給server
             server.listen(port, addr);
             return this;
         };
     };
 var instance = new evolve({//利用設定參數實體化
     basedir: path.join(__dirname, '/../www'),
     dirindex: ['index.htm','index.html','default.htm']
 });
 instance.listen(8443, '127.0.0.1');
 console.log('server started.');

為了保證設定可能的變化能被處理,在測試的時候需要調整dirindex參數,讓實際存在的index檔在設定中的順序不一樣,這樣比較能確定程式的邏輯沒問題。

現在需要的參數有對應到檔案系統的路徑以及預設的index檔,為了程式的彈性,只好調整一下架構:

  1. 用一個constructor包裝伺服器程式,這樣才方便在每次實體化時把設定的參數傳給他
  2. server物件只是constructor函數中的一個變數,不過他在實體化之後還需要用listen操作所以寫一個簡單的wrap函數來操作他

即使是這樣,每次測試不同設定組合時,還需要改這支程式,有點麻煩,解決之道是把他作成模組,這個明天再來處理。

相關文章


上一篇
node.js伺服器實戰(7) - mime支援
下一篇
node.js伺服器實戰(9) - 模組化
系列文
node.js伺服器實戰33

1 則留言

0
chiounan
iT邦研究生 1 級 ‧ 2011-10-19 09:50:58

讚很認真

我要留言

立即登入留言