發表文章

目前顯示的是 十一月, 2011的文章

NodeJS + Express 實作檔案上傳

Express Web Framework』是基於『Connect Middleware Framework』所開發,大部份的常見功能,藉由 Connect 本身支援或 Connect 的第三方(Third-party)模組,就可以實作出來。如果要實作檔案上傳的功能,可以使用第三方模組『connect-form』來達成。

直接透過 npm 安裝需要的模組:
npm install connect-form
在 app.js 中實作:
var express = require('express'); var form = require('connect-form'); var app = module.exports = express.createServer(); app.configure(function(){ app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(form({keepExtensions: true,uploadDir: __dirname + '/uploads'})); app.use(app.router); app.use(express.static(__dirname + '/public')); }); app.get('/', function(req, res) { res.send('<form method="post" enctype="multipart/form-data">' + '<p>Image: <input type="file" name="image" /></p>' + '<p><inp…

在 NodeJS + Express 使用 Cookie-based Session

開發網站的人應該對 Session 都不陌生,主要是用於 Client 與 Server 之間的溝通和狀態記錄。底層的實作細節本文就不多說明,若仍不理解他的用途,只要知道它可以讓你在不同頁面之間傳遞資料,像是登入狀態等。

一般標準的『Express』利用『Connect Middleware Framework』(之後簡稱 Connect)中的模組來實作 Session 的,而預設的方法是使用 MemoryStore 的方式,也就是將 Session 資料存放於記憶體上。若你開發的是中大型的網站,也可以使用 Connect 的第三方模組『connect-redis』,利用『Redis』這樣的 Key-Value Database 來存放 Session 的資料。這些在 NodeJS + Express 的各類開發文獻中相當常見,你可以從許多網站上找到使用方法。

不過,也許你仍不滿足,希望使用近年來興起的 Cookie-based Session,Connect 也有第三方模組『cookie-sessions』可以使用。

可以直接使用 npm 安裝:
npm install cookie-sessions
在你的 app.js 這樣使用:
var express = require('express'); var CookieStore = require('cookie-sessions'); var app = module.exports = express.createServer(); app.configure(function(){ app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(express.cookieParser()); app.use(CookieStore({ secret: 'FredChien' })); app.use(app.router); app.use(expr…

千萬別相信 Android 上的應用程式

或許有些過於危言聳聽,但我們確實得正視這樣的議題:『資料無故從手機中消失』。這是可能發生的問題,原因在於 Android Dalvik VM 的 Garbage Collection 機制太過強大,如果程式開發者在寫程式的過程中都沒注意到這問題,那這肯定是個不定時炸彈。

話說,寫過 Android Application 的人應該都很習慣了變數宣告後,用完了就不管他,彷彿系統會有無限量供應的記憶體一般。不過,這對『慣C』一族來說,永遠是種荒繆的事,實在無法想像『憑什麼』不用釋放記憶體。其實說穿了,這一切是 VM 裡面的 Garbage Collection 在『Hold 住』場面,他會自動將目前 Reference 數量稀少的記憶體回收,以避免系統記憶體被用光後又不釋放。而所有回收的動作,有一系列『聰明』的演算法,有興趣的人可以自己去找相關資訊閱讀。

但是別以為 Garbage Collection 可以聰明到百分之百準確知道,什麼東西回收後是對系統或是應用程式無傷的,因為這就算要人腦來判斷,也一定會犯錯。更者,也別以為 Garbage Collection 不太會動當前正在跑的程式,因為只要符合條件,就算是你程式當前不斷在用的變數,也可能消失被回收,導致程式錯亂,就像被鬼憑空抓走一般。

如果你認為這只是理論,那你就錯了,這問題實際發生在最近筆者幫忙救火的案子裡。詳細情況是,這是瀏覽器相關的案子,當時我們宣告了幾個 Private 變數,然後使該變數在使用者操作觸發後,會被設定了一些數值供接下來的許多運算使用。一般情況下,我們實作的程式都很正常,不過,一旦開到比較複雜或充滿 JavaScript 的網站後,我們的程式彷彿就開始像中邪,完全不照我們的想像去執行,無論怎麼找問題,也找不出個所以然。

由於問題的發生是過程中變數無故被歸零,而我們又確定沒有任何一段自己的程式會讓他歸零,所以只剩下一種可能:『Garbage Collection 為了因應 WebView 過多的需求,而把變數給回收了。』

最後,我們將這變數設為 static 以解決這問題。不過,雖然用 static 暫時解決了問題,那也只是減少變數不被回收的機會,並不是最妥當的做法。

後記

別小看這問題,其實在 Android Framework 中也處處藏滿類似的問題,只是不知道什麼時候會爆出來而已。而這次…

自認帥氣的 WebSocket 簡單命令處理模型

最近參與的一個 Project,需要在 WebSocket 下實作許多機制,這著實讓人傷透腦筋。又由於 JavaScript 完全是非同步(asynchronous)的設計概念,若遇到必需等待 Server 回應後才能繼續執行的工作,處理起來可是一件異常麻煩的事。雖然很熟悉運用回調函數(Callback Function)和暱名函數(Anonymous Function)來做,但一層包一層的設計,總讓人覺得進入無限階層的夢境地獄,什麼時候醒來都不知道。

這是筆者要達成的需求:『發送自己定義的命令去 Server,然後等待 Server 回應,一旦收到 Server 回應就可以繼續往下處理。』

一般的情況下,多數人都會這樣做(這理使用 Socket.IO 來建立 WebSocket,並和 Server 要當前時間為例):
/* Define handler to receive response from server */ socket.on('Clock', function(data) { /* Do something */ alert(data); }); /* Send command to server */ socket.emit('Clock', 'Time');
可是,並非每次對 Server 的請求,都希望透過 alert() 跳出結果,我們有時只是想要利用 Server 給的時間做一些其他處理,雖然是下同樣的命令,但後續處理完全不一樣。於是,筆者,設計了這樣的方式,簡單的去處理這種問題:
var command = { 'Time': [], 'Date': [] /* You can define more commands */ }; socket.on('Clock', function(data) { if (command[data.command].length) { for (var index in command[data.command]) command[data.command][index](data.result); …

使用 Jade 快速製作 HTML Template

如果你用 NodeJS 和『Express Web Framework』來寫網站,又參考官方給的範例程式,『Jade』應該是你首選的 Template Engine。不過 Jade 相當容易,如果你已經很熟悉 HTML,學習它不會是件難事。

Jade 用來表示每一個 HTML Tag 的格式:
<tag>(<attributes>) <inner content>或是<tag>(<attributes>)= <inner content> ex: img(src='/images/logo.jpg') ex: a(href='http://www.mandice.com/') Mandice ex: title= This is Jade Example
使用縮排描述巢狀結構( 如同 Python):
Jade 語法: html   head     title= This is Jade Example   body     Hello World 結果: <html>         <head>                 <title>This is Jade Example</title>         </head>         <body>Hello World</body> </html>
賦予 Element 一個 ID 有兩種方式:
div(id='element1') 或是 div#element1
引入並使用另一個 Jade 檔案:
div#element1= partial('another.jade')
賦予 Tag 有多個 Attributes 有兩種方法:
使用『,』連接多個 Attribute: img(src='/images/logo.jpg', title='This is a Logo') 使用換行連接多個: img(         src='/images/logo.jpg'         title='This is a …

我如何看待 NodeJS

圖片
其實,這是篇推薦文,但推薦的角度和坊間很多人不一樣,所以這也是為什麼標題下『我如何看待 NodeJS』。

誠如大家所知,『NodeJS』原先被開發出來的目的,是為了解決 Web Server 效能的問題,其採用 Google Chrome/Chromium 使用的『Google V8 Javascript Engine』做為直譯器引擎。最特別的是,NodeJS 讓開發者完全可以用 JavaScript 來開發整個伺服器端的所有程式,這意味你可以不用再使用 Python、PHP、Perl、Ruby、ASP 等其他的語言,只需要學會 JavaScript 就可以將網站通通搞定。也因為幾乎所有的 Web 開發者都熟悉 JavaScript,NodeJS 很理所當然的成為一個 Web 圈內受很多人擁護的新技術,在各大 Cloud Hosting 也都開始有支援。

當然不只是如此, NodeJS 也吸收了各方面的經驗,提供應用程式框架(Framework)讓開發者可以快速開發。平心而論,比其他的語言更能兼固快速開發和效能的問題。

談到這裡,還是僅止於坊間多數人介紹的內容,筆者認為,如果只是這樣,也未免小覻了 NodeJS。

事實上,NodeJS 就是 Original JavaScript Without Browser + Libraries,在舊有的 JavaScript 抽離瀏覽器後,再上加上更多 System-level Library 的支援。這讓我們可以重新看待 JavaScript 這個語言,因為它不再只是限於『特定領域』使用,而是提升至『System Level』。

我們可以這樣認定:『JavaScript 已經可以和 Python 相提並論』。因此,使用 JavaScript 寫一支系統應用程式或是桌面應用程式,已經不再是夢,而是伸手可及。如果你有印像,HP WebOS 就是率先引入 NodeJS 的先行者,讓原本被視為 Web 技術的 JavaScript,跳出舊有框框,進入桌面系統的領域。

目前,NodeJS 仍持續發展中,許多函式庫支援也被慢慢的被實作出來。有時為了效能考量,我們也可以自己使用 C/C++ 為他開發更多 Library/Module。可以期待,未來 NodeJS 將會更為強大。

使用 NodeJS + Express + Socket.IO 實作 WebSocket 服務

一直處於假標準狀態的 HTML5,過程中一直有變化,讓人無法放心使用。不過到了今年,HTML5 總算進入了準決賽的階段,大部份功能已經確定下來,其中 WebSocket 就是最讓人關切的項目之一,因為這意味著未來 Web 不再只是單次性的觸發服務,而是可以讓使用者端與伺服器長時間處於連線狀態,並進行即時性的資料傳交換。

關於 WebSocket,彷間許多隨 HTML5 起舞的人,其實都說明不夠清楚,多半只強調能達成 TCP Socket 形式的連線,和無所不能的優點。其實,WebSocket 並非是我們所知的原生 Socket ,而只是一種架構於 HTTP Protocol 上的延伸定義,所以換句話來說,不能直接拿來連線到非 HTTP 以外的通訊協定。

至於它的做法,就是在瀏覽器向伺服器要資料時,在 Request Header 裡加上『Connection:Upgrade』來告訴伺服器:『我要改變連線形態』。然後伺服器會依照瀏覽器給的 WebSocket 相關標頭(header)和交握用的金鑰(Key),進行認證和改變處理方式。進入 WebSocket 連線的客戶端,就有如在使用 TCP Socket 或 Telnet 一樣,可以隨意在任意時間點傳送資料給伺服器處理,伺服器也可以在這連線下即時回應。所以就某方面來說,這剛好可以含蓋並取代過去 Web 1.0 的 Refresh Page 和 Web 2.0 後的 Long-polling 技術。

寫過網路程式的人都知道,如何定義 Protocol 才是傷腦筋的事,開啟了一個『類 Socket』意味著我們又回到了過去的年代,要自己解決 Protocol 的定義。不過也已經有現成的 Library 可以使用,許多問題我們已經不用擔心,本文將提到的 Socket.IO 就是其中之一。此外,由於 WebSocket 需要 Client/Server 同時實作,所以,這些 Library 多半都包括了兩部份的實作。

Server 端,使用 NodeJS + Express web framework + Socket.IO(0.8.6):
/* Module dependencies */ var express = require('express'); var io = require('sock…