不得不說,基本上咱們還沒到寫框架的日子,前面這些,徹底都是在寫一個web服務器(並且還沒寫完)。 html
今天的工做主要是整理。 node
首先來談談Node.js中模塊的概念。基本上咱們之前的工做就是:寫一個js文件,而後根據相對路徑來引用它。這裏出現一個問題,就是相對路徑實際上並不穩定,並且咱們後期可能把全部框架級別的內容單獨放置在一個文件夾中,這時候一樣會改變相對路徑,因此須要引入模塊來實現require時候的穩定。 web
Node.js中從路徑Y中require(X)的流程爲: 數據庫
1. 若是X是核心模塊(如http、fs等),返回核心模塊
2. 若是X以'./'或者'../'或者'/'開始,首先嚐試以文件方式加載,失敗則嘗試以文件夾方式加載
3. 若是2失敗,則嘗試在node_modules目錄下查找該模塊 編程
更詳細內容能夠看這個:
Node.js API json
這裏咱們使用第三種,就是把全部框架級別的文件單獨放在node_modules下的一個文件夾下,並根據CommonJS關於Package的規範來從新整理文件夾結構。 api
首先是文件夾結構:
頂層文件夾中,包含一個文件:package.json,用於描述包信息
二進制文件放在/bin下
Javascript文件放在/lib下
文檔放在/doc下
測試文件放在/test下 服務器
原文:http://wiki.commonjs.org/wiki/Packages/1.0#Package_Directory_Layout session
整理之後,簡單的寫一下package.json 框架
{ "name" : "restjs", "main" : "./lib/main.js", "maintainers" : [ { "name" : "Jeky Cui", "email" : "Jeky.Cui@gmail.com" } ] }好,模塊文件整理部分到此結束。
下面開始分離框架部分。這裏遇到的問題依然是路徑,實在沒辦法了,只好使用fs.realpath來解決:
var root = fs.realpathSync('./') + '/';
這裏須要解釋一下,我不是不喜歡異步編程,只是以爲服務器啓動期間徹底能夠用同步來寫,簡單明瞭。
另外一件事情就是把配置獨立出來,若是用戶須要修改配置,那麼就在構造Dispatcher時修改就能夠了。而且,我在配置裏添加了一項叫作welcomeFile,若是配置了welcomeFile,那麼當訪問網站首頁時,會直接跳轉至welcomeFile。
module.exports = { staticPath : 'static', maxAge : 1000 * 60 * 60 * 24 * 7, welcomeFile : 'index.html', devMode : true, modulePath : 'modules', indexName : 'index', viewFilename : 'views.js' }
好,到此爲止,徹底分離了服務器&框架部分和業務邏輯部分。實際上到目前爲止,已經寫完了一個基本可用的靜態服務器。
下面開始作動態部分。主要內容有:
1. 請求的封裝
2. session的處理
3. 模板渲染
4. 數據庫
今天完成請求封裝部分。
實際上對於GET請求的封裝,Node.js已經幫咱們完成了:
http://nodejs.org/api/querystring.html#querystring_querystring_parse_str_sep_eq_options
function wrapParam(req){ if(req.method == 'GET'){ var queryStr = url.parse(req.url).query; if(!queryStr){ return {}; } return qs.parse(queryStr); }else if(req.method == 'POST'){ // TODO } }下面只須要對於POST進行解析並封裝就能夠了。POST請求會觸發request的'data'時間,只要監聽這個事件就能夠了。這裏先暫時忽略掉文件上傳這回事。
function wrapParam(req){ if(req.method == 'GET'){ var queryStr = url.parse(req.url).query; if(!queryStr){ return {}; } return qs.parse(queryStr); }else if(req.method == 'POST'){ req.on('data', function(chunk){ result = qs.parse(chunk.toString()); }) } }好是挺好,可是異步編程是沒法直接把這個result返回的,因此還須要引入回調函數。
function wrapParam(req, callback){ if(req.method == 'GET'){ var queryStr = url.parse(req.url).query; if(!queryStr){ callback({}); } callback(qs.parse(queryStr)); }else if(req.method == 'POST'){ req.on('data', function(chunk){ callback(qs.parse(chunk.toString())); }) } }好,到目前爲止都很順利。明天起來完成文件上傳的部分。
P.S. 謝謝 @mingshun 的指導,單純檢測data事件會致使POST數據不完整,須要在end事件時拼接POST數據,代碼修改成:
function wrapParam(req, callback){ if(req.method == 'GET'){ var queryStr = url.parse(req.url).query; if(!queryStr){ callback({}); } callback(qs.parse(queryStr)); }else if(req.method == 'POST'){ var chunks = []; var length = 0; req.on('data', function(chunk){ chunks.push(chunk); length += chunk.length; }) req.on('end', function(){ var buffer = undefined; if(chunks.length == 1){ buffer = chunks[0]; }else{ buffer = new Buffer(length); } var len = 0; $(chunks).each(function(chunk){ chunk.copy(buffer, len); len += chunk.length; }); var param = qs.parse(buffer.toString()); callback(param); }) } }