iT邦幫忙

DAY 2
1

Node.js 學習筆記系列 第 2

Node.js學習筆記一:Node.js的Hello World

今天來看看Node.js風格的Hello World,以下是我的學習重點

  1. 事件驅動與**非同步(Asynchronous)**是Node.js的兩大核心特色。這個例子都有簡單涉獵到。

  2. 回呼(Callback)函數則是事件驅動(Event Driven)的重點。

  3. Http伺服器的基本操作。重點在**req(Request:請求)res(Response:回應)**兩個參數的理解。

  4. 最後一個小點是,不要混淆Console的輸出(console.log)與網頁的輸出(res.write)。

簡單地輸出"Hello World"字串的例子未免浪費時間,還是直接先來看Http伺服器版的:

var vhttp = require("http");

function onRequest(req, res) {
  console.log("Request received.");
  res.writeHead(200, {"Content-Type": "text/plain"});
  res.write("Hello World");
  res.end();
}

vhttp.createServer(onRequest).listen(3000);

console.log("Server has started to listen at port: 3000.");

將檔案保存為index.js,再使用node index.js 來執行。首先會看到Console顯示:"Server has started to listen at port: 3000."

用瀏覽器打開:http://localhost:3000,網頁會顯示"Hello World";同時Console會輸出兩次:"Request received."。至此,整個程式跑完。接下來我們來一句一句地解讀。

一、用Node.js建立http伺服器

Node.js有意思的地方之一就是可以自行建立http伺服器,換言之,你可以不用Apache之類的伺服器程式來運行你的網站,不用再為Apache的config頭大。但副作用是你自己要處理所有原本由Apache幫你做的事情,例如路由(Routing)等。聽起來很恐怖嗎?不用擔心,早有人開發了Express.js來幫你,這我們以後再詳談。

要用Node.js來建立http伺服器,首先要使用Node.js自帶的http模組。我們"requie"該模組,再將之賦值給"vhttp"變數。之所以加"v"只是提醒大家,這是個變數。熟悉了以後,完全可以把"v"拿掉。

然後我們可以用模組提供的**createServer()**函數來建立一個伺服器。這個函數接受一個回呼函數(Callback Function)作為參數。

所謂回呼函數(Callback Function):就是只有當事件被觸發的時候才執行的函數。

對createServer()來講,所謂事件就是指有人訪問網站,或著說:有對網站的請求(request)進來。即,當有人訪問這個網站,就執行onRequest()這個函數。所以真正網站的內容是在onRequest()函數裡產生。另外要注意到這裡是將onRequest()這個函數作為參數傳給createServer(),將函數作為參數傳遞也是滿特別的。

而.createServer()的返回值則是一個物件,這個物件有一個listen()的函數,讓你決定要這個伺服器要監聽哪一個port,這裡我選的是"3000",所以我在瀏覽器上輸入的網址是:localhost:3000。你可以將它改為你喜歡的任何數字,但要注意一些預設的port,像"80"是http的預設port,"21"是FTP的預設等。

這裡我們將listen()函數接在createServer()後面是指,用createServer()返回的物件來執行listen()函數。要把它寫完整,可以這樣:

var server = http.createServer(onRequest);
server.listen(3000);

先用server變數裝著返回的物件,再執行這個物件listen()函數。

這樣一個http伺服器就成功建立了。

二、回呼函數onRequest()處理請求(request)並作出回應(response)。

當有人訪問這個http伺服器時,onRequest()就會被觸發。onRequest()有兩個參數:req和res,分別代表Request(請求)與Response(回應)。從字面也不難理解:

Request: 是用戶送來的請求,包括網址及其參數等,如:localhost:3000/index?user=tester。我們可以根據這裡的信息通過回應(Response)將訪客導引至相應的頁面或執行相關函數等。

Response: 是伺服器對請求的回應。根據用戶請求的內容作出反應,在這個例子裡,當有請求進來,不論任何請求,都輸出"Hello World"字串。例子中,將回應分成三步:

一、res.writeHead(200, {"Content-Type": "text/plain"}):給出http的head資訊,其中"200"代表正常,無錯誤。而 {"Content-Type": "text/plain"}則是檔案的格式,這裡是純文字檔案。

二、res.write("Hello World"):這一步是寫進http的body,即為實際顯示內容。

三、res.end():代表結束回應,沒有這句會出錯。

實際上,第二跟第三步可以合併,變成:

res.end("Hello World");

也能成功輸出字串。

三、Console輸出記錄(log)。

為了確定程式真的做到我們想要的內容,我們可以在Console輸出一些記錄。這個例子共有兩句Console輸出,一句在回呼函數onRequest()裡面;另一句在程式最後。

onRequest()裡面那句就是每次有請求(request)進來就執行。你會發現一次訪問,會輸出兩次"Request received."。這是因為伺服器除了請求網頁之外,還會請求該網站的favicon.ico,即,URL:"localhost:3000/favicon.cio"也會被請求。所以是兩次。

你有沒有發現,第二句的Console輸出是在程式的最後,但卻比較先輸出。按照正常的順序,應該是onRequest()結束了,才會執行最後那句Console輸出。但實際情況則是相反。這就是Node.js的另一大特性:非同步(Asynchronous)。

非同步(Asynchronous)是指程式不會等待上一句結束,再執行下一句。當上一句卡住時,下面的程式會繼續執行。

不難想像這種特性對網頁來講是多麼的有用。最簡單的例子就是,當你的網頁還在加載圖片時,其他網頁元素不用等圖片就開始顯示出來,明顯會大大增加網頁載入的速度,也提昇用戶體驗。

四、Ctrl + Break 來結束程式

你應該發現了,這個程式一直在Console執行中,必須使用Ctrl + Break來強制中斷。每次你修改你的程式碼後,要重新執行程式,也要再用一次Ctrl + Break。如果不想這麼麻煩,可以使用Nodemon模組,它可以持續監視你的程式碼,每當你有所改動,並保存,它就會自動重新啟動程式。你只要更新網頁就能看到結果。

這個http伺服器版的Hello World例子講解就到此為止。來整理一下今天學了什麼。

五、總結

回顧一下開頭的那幾個重點:

  1. 事件驅動非同步
    --事件驅動主要體現在回呼函數的機制;而非同步則是較後程式可以先執行。

  2. 回呼(Callback)函數
    --回呼函數的重點是:事件觸發才執行。

  3. Http伺服器的基本操作。重點在**req(Request:請求)res(Response:回應)**兩個參數的理解。
    --根據請求(用戶透過URL送進來)作出回應。

  4. 最後一個小點是,不要混淆Console的輸出(console.log)與網頁的輸出(res.write)。
    --這就不多講了。

下一篇,我想可以研究一下請求(Request)的部分。這個例子太簡單,完全沒有請求的部分,下篇專門討論請求與回應。

參考資料:

  1. The Node Beginner Book

[image credit: [Vo Minh](https://www.flickr.com/photos/titi_the_dreams_catcher/" style="line-height: 1.6;)]

同步發表於我的部落格: NodeJust.com


上一篇
Node.js 學習筆記序:學習資源匯整
下一篇
Node.js學習筆記二:Node.js路由(Routing)處理基礎
系列文
Node.js 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言