Node.js 學習筆記之三:構建 Web 服務
示例3. 構建 Web 伺服器
這部分示例將致力於用 Node.js 模擬一個類似於 Apache 的 Web 伺服器,處理瀏覽器端的請求,將相關的頁面響應給瀏覽器。首先,我們要在code
目錄下執行mkdir 03_webSever
命令來建立用於存放這一組示例的目錄。然後執行以下步驟:
-
在
code/03_webSever
目錄下執行mkdir www
命令,建立網站目錄,然後在其中建立index.htm
和login.htm
兩個 HTML 檔案以及一個名為style.css
的 CSS 檔案:-
index.htm:
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8" /> <link rel="stylesheet" type="text/css" href="style.css" /> <title>首頁</title> </head> <body> <h1>你好,nodejs!</h1> <p> <a href="login.htm">請登入!</a> </p> </body> </html>
-
login.htm:
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8" /> <link rel="stylesheet" type="text/css" href="style.css" /> <title>登入頁面</title> </head> <body> <h1>你已經登入。。。</h1> <p> <a href="index.htm">回首頁!</a> </p> </body> </html>
-
style.css:
body { background: gray; }
-
-
在
code/03_webSever
目錄下執行touch 03-webServer.js
命令,建立指令碼檔案,並輸入如下程式碼:const http = require('http') const fs = require('fs') const server = http.createServer() server.on('request', function(req, res) { const webRoot = './www' const url = req.url if ( url === '/' ) { url = '/index.htm' } fs.readFile(webRoot+url, function(err, data) { if ( err !== null ) { console.error('錯誤資訊:' + err.message) return res.end('<h1>404 頁面沒找到!</h1>') } res.end(data) }) }) server.listen(8080, function(){ console.log('請訪問http://localhost:8080/,按Ctrl+C終止服務!') })
-
儲存所有檔案後,在
code/03_webSever
目錄下執行node 03-webServer.js
命令,然後開啟瀏覽器並訪問http://localhost:8080/
,就會看到如下頁面:
示例4. 使用art-template
模版引擎生成網頁
這一部分本示例將以生成個人資訊頁面為例,演示在伺服器端基於 Node.js 使用art-template
模板引擎來生成網頁。為此,我們需要在code
目錄下執行mkdir 04_templatingEngine
命令來建立用於存放這一組示例的目錄。
1. 單模版渲染
首先來示範一下如何使用art-template
模版引擎的渲染單一模版檔案,請跟著以下步驟來構建示例:
-
在
code/04_templatingEngine
目錄下執行npm install art-template --save
命令,安裝將art-template
包安裝到當前示例專案中。 -
在
code/04_templatingEngine
目錄下執行touch singleTpl.htm
命令,建立一個模版檔案,並在其中輸入以下程式碼:<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8" /> <link rel="stylesheet" type="text/css" href="style.css" /> <title>{{ name }}的個人資訊</title> </head> <body> <h1>{{ name }}的個人資訊</h1> <table> <tr><td>姓名:</td><td>{{ name }}</td></tr> <tr><td>年齡:</td><td>{{ age }}</td></tr> <tr><td>性別:</td><td>{{ sex }}</td></tr> <tr> <td>愛好:</td> <td>{{ each items }} {{ $value }} {{ /each }}</td> </tr> </table> </body> </html>
-
在
code/04_templatingEngine
目錄下執行touch 04-useTemplating_engine.js
命令,建立一個指令碼檔案,具體如下:const http = require('http') const fs = require('fs') const template = require('art-template') class human { constructor(name, age, sex, items=[]) { this.name = name this.age = age this.sex = sex this.items = items } } const server = http.createServer() server.on('request', function(req, res){ const url = req.url let boy = null if ( url === '/' ) { boy = new human('凌傑', '37', '男', ['看書', '看電影','旅遊']) } else if ( url === '/wang' ) { boy = new human('蔓兒', '25', '女', ['看書', '看電影','寫作']) } if ( boy === null ) { return res.end('<h1>404 頁面沒找到!</h1>') } fs.readFile('./singleTpl.htm', function(err, data){ if ( err !== null ) { return res.end('<h1>404 沒找到模版檔案!</h1>') } const strHtml = template.render(data.toString(), { name : boy.name, age : boy.age, sex : boy.sex, items: boy.items }) res.end(strHtml) }) }) server.listen(8080, function(){ console.log('請訪問http://localhost:8080/,按Ctrl+C終止服務!') })
-
儲存所有檔案後,在
code/04_templatingEngine
目錄下執行node 04-useTemplating_engine.js
命令,然後開啟瀏覽器並訪問http://localhost:8080/wang
,就會看到如下頁面:
2. 多模版組合渲染
在同一 Web 應用中,所有的頁面通常都由相同的頭部和底部元素,所以為了減少程式碼的冗餘,提高重用率,開發者們通常會考慮將重複的部分獨立成一個單獨的模版檔案,然後用相互包含的方式組合成頁面。下面就繼續以art-template
模板引擎為例來演示一下如何將多個模版組合渲染成單一的 HTML 頁面,其具體步驟如下:
-
在
code/04_templatingEngine
目錄下執行touch tpl1.art tpl2.art
命令,建立兩個模版檔案,然後在這兩個檔案中分別輸入以下程式碼:-
tpl1.art :
<header> <h1>檢視個人資訊</h1> <br> </header>
-
tpl2.art :
<footer> <div> <p>© 2016 owlman.org;本站系純HTML5站點。</p> </div> </footer>
-
-
在
code/04_templatingEngine
目錄下執行touch multiTpl.htm
命令建立用於組合的 HTML 頁面檔案,並在其中輸入以下程式碼:<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8" /> <link rel="stylesheet" type="text/css" href="style.css" /> <title>檢視個人資訊</title> </head> <body> {{ include './tpl1.art' }} <h2>{{ name }}的個人資訊</h2> <table> <tr><td>姓名:</td><td>{{ name }}</td></tr> <tr><td>年齡:</td><td>{{ age }}</td></tr> <tr><td>性別:</td><td>{{ sex }}</td></tr> <tr> <td>愛好:</td> <td>{{ each items }} {{ $value }} {{ /each }}</td> </tr> </table> {{ include './tpl2.art' }} </body> </html>
-
在
code/04_templatingEngine
目錄下執行cp 04-useTemplating_engine.js 04-useTemplating_engine2.js
命令,將之前的程式碼複製一份,並修改如下:const http = require('http') const fs = require('fs') const template = require('art-template') template.defaults.root = __dirname // 配置模版的查詢根目錄 class human { constructor(name, age, sex, items=[]) { this.name = name this.age = age this.sex = sex this.items = items } } const server = http.createServer() server.on('request', function(req, res){ const url = req.url let boy = null if ( url === '/' ) { boy = new human('凌傑', '37', '男', ['看書', '看電影','旅遊']) } else if ( url === '/wang' ) { boy = new human('蔓兒', '25', '女', ['看書', '看電影','寫作']) } if ( boy === null ) { return res.end('<h1>404 頁面沒找到!</h1>') } fs.readFile('./multiTpl.htm', function(err, data){ // 修改了要讀取的模版檔案 if ( err !== null ) { return res.end('<h1>404 沒找到模版檔案!</h1>') } const strHtml = template.render(data.toString(), { name : boy.name, age : boy.age, sex : boy.sex, items: boy.items }) res.end(strHtml) }) }) server.listen(8080, function(){ console.log('請訪問http://localhost:8080/,按Ctrl+C終止服務!') })
-
儲存所有檔案後,在
code/04_templatingEngine
目錄下執行node 04-useTemplating_engine2.js
命令,然後開啟瀏覽器並訪問http://localhost:8080
,就會看到如下頁面:
3. 多模版繼承渲染
當然,如果重複的元素只有頭部和尾部的話,有時候使用模版繼承語法來渲染頁面會是一個更好的選擇,下面就來繼續演示一下art-template
模板引擎的繼承語法來渲染 HTML 頁面,其具體步驟如下:
-
在
code/04_templatingEngine
目錄下執行touch baseTpl.art
命令,建立父模版檔案,然後在該檔案中輸入以下程式碼:<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8" /> <link rel="stylesheet" type="text/css" href="style.css" /> <title>{{ name }}的個人資訊</title> </head> <body> <header> <h1>檢視個人資訊</h1> <br> </header> {{ block 'message' }} {{ /block }} <footer> <div> <p>© 2016 owlman.org;本站系純HTML5站點。</p> </div> </footer> </body> </html>
-
在
code/04_templatingEngine
目錄下執行touch extendTpl.htm
命令,建立子模版檔案,然後在該檔案中輸入以下程式碼:{{ extend 'baseTpl.art' }} {{ block 'message' }} <h1>{{ name }}的個人資訊</h1> <table> <tr><td>姓名:</td><td>{{ name }}</td></tr> <tr><td>年齡:</td><td>{{ age }}</td></tr> <tr><td>性別:</td><td>{{ sex }}</td></tr> <tr> <td>愛好:</td> <td>{{ each items }} {{ $value }} {{ /each }}</td> </tr> </table> {{ /block }}
-
在
code/04_templatingEngine
目錄下執行cp 04-useTemplating_engine.js 04-useTemplating_engine3.js
命令,將之前的程式碼複製一份,並修改如下:// 用Node.js生成動態頁面 // 作者:owlman // 時間:2019年07月12日 const http = require('http') const fs = require('fs') const template = require('art-template') template.defaults.root = __dirname class human { constructor(name, age, sex, items=[]) { this.name = name this.age = age this.sex = sex this.items = items } } const server = http.createServer() server.on('request', function(req, res) { const url = req.url let boy = null if (url === '/') { boy = new human('凌傑', '37', '男', ['看書', '看電影','旅遊']) } else if (url === '/wang') { boy = new human('蔓兒', '25', '女', ['看書', '看電影','寫作']) } if (boy === null) { return res.end('<h1>404 頁面沒找到!</h1>') } fs.readFile('./extendTpl.htm', function(err, data) { if ( err !== null ) { return res.end('<h1>404 沒找到模版檔案!</h1>') } const strHtml = template.render(data.toString(), { name : boy.name, age : boy.age, sex : boy.sex, items: boy.items }) res.end(strHtml) }) }) server.listen(8080, function(){ console.log('請訪問http://localhost:8080/,按Ctrl+C終止服務!') })
-
儲存所有檔案後,在
code/04_templatingEngine
目錄下執行node 04-useTemplating_engine3.js
命令,然後開啟瀏覽器並訪問http://localhost:8080
,就會看到與之前相同的頁面。
示例5. Web 表單處理
這一部分示例將致力於演示用 Node.js 處理 Web 表單,我們將會分別示範如何用get
和post
兩種方法來處理表單的請求。首先,我們要在code
目錄下執行mkdir 05_webForm
命令來建立用於存放這一組示例的目錄。
1. get 方法
先用一個資訊查詢程式來演示一下如何處理使用get
方法來發送請求的表單。首先,在code/05_webForm
目錄下執行mkdir get_form
命令,並執行以下步驟:
-
在
code/05_webForm/get_form
目錄下執行npm install art-template
命令,將art-template
安裝到當前示例專案中。 -
在
code/05_webForm/get_form
目錄下執行touch index.htm
,建立一個模版檔案,具體如下:<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>個人資訊查詢</title> </head> <body> <h1>個人資訊查詢</h1> <form action="/query" method="GET"> <label for="message">請輸入要查詢的姓名:</label> <input type="text" name="qname" /> <input type="submit" value="查詢" /> </form> <br /> {{ if name }} <table> <caption>{{ name }}的個人資訊</caption> <tr><td>姓名:</td><td>{{ name }}</td></tr> <tr><td>年齡:</td><td>{{ age }}</td></tr> <tr><td>性別:</td><td>{{ sex }}</td></tr> <tr> <td>愛好:</td> <td>{{ each items }} {{ $value }} {{ /each }}</td> </tr> </table> {{ else if query_error }} <h2>沒有找到相關資訊!</h2> {{ /if }} </body> </html>
-
在
code/05_webForm/get_form
目錄下執行touch app.js
,建立一個指令碼檔案,具體如下:const http = require('http') const fs = require('fs') const url = require('url') const template = require('art-template') class human { constructor(name, age, sex, items=[]) { this.name = name this.age = age this.sex = sex this.items = items } } const db = [ new human('凌傑', '37', '男', ['看書', '看電影','旅遊']), new human('蔓兒', '25', '女', ['看書', '看電影','寫作']), new human('張語', '32', '女', ['看書', '旅遊','繪畫']) ] const server = http.createServer(function(req, res){ const query = url.parse(req.url, true) let obj = null let query_error = false if ( query.pathname === '/' ) { query_error = false } else if (query.pathname === '/query') { for(let i = 0; i < db.length; ++i) { if (db[i].name == query.query["qname"]) { obj = db[i] } } if ( obj === null ) { query_error = true } } else { return res.end('<h1>404 頁面沒找到!</h1>') } fs.readFile('./index.htm', function(err, data){ if ( err !== null ) { return res.end('<h1>404 沒找到模版檔案!</h1>') } let strHtml = null if ( obj !== null ) { strHtml = template.render(data.toString(), { name : obj.name, age : obj.age, sex : obj.sex, items: obj.items, query_error: query_error }) } else { strHtml = template.render(data.toString(), { name : false, query_error: query_error }) } res.end(strHtml) }) }) server.listen(8080, function() { console.log('請訪問http://localhost:8080/,按Ctrl+C終止服務!') })
-
儲存所有檔案後,在
code/05_webForm/get_form
目錄下執行node app.js
命令,結果如下:
2. post 方法
先來演示如何處理使用post
方法來發送請求的表單。首先,在code/05_webForm
目錄下執行mkdir post_form
命令,並執行以下步驟:
-
在
code/05_webForm/get_form
目錄下執行npm install art-template
命令,將art-template
安裝到當前示例專案中。 -
在
code/05_webForm/post_form
目錄下執行touch index.htm
,建立一個模版檔案,具體如下:<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>個人資訊管理</title> </head> <body> <h1>個人資訊管理</h1> <table> <caption>個人資料表</caption> <tr><th>姓名</th><th>年齡</th><th>性別</th><th>愛好</th></tr> {{ each db }} <tr> <td>{{ $value.name }} </td> <td>{{ $value.age }} </td> <td>{{ $value.sex }} </td> <td>{{ each $value.items }} {{ $value }} {{ /each }}</td> </tr> {{ /each }} </table> <form action="/add" method="POST"> <table> <caption>錄入新人員</caption> <tr><td>姓名:</td><td><input type="text" name="uname" /></td></tr> <tr><td>年齡:</td><td><input type="text" name="age"></td></tr> <tr><td>性別:</td><td><input type="text" name="sex"></td></tr> <tr><td>愛好:</td><td><input type="text" name="items"></td></tr> </table> <input type="submit" value="新增" /> </form> </body> </html>
-
在
code/05_webForm/post_form
目錄下執行touch app.js
,建立一個指令碼檔案,具體如下:const http = require('http') const fs = require('fs') const url = require('url') const querystring = require('querystring') const template = require('art-template') class human { constructor(name, age, sex, items=[]) { this.name = name this.age = age this.sex = sex this.items = items } } const db = [ new human('凌傑', '37', '男', ['看書', '看電影','旅遊']), new human('蔓兒', '25', '女', ['看書', '看電影','寫作']), new human('張語', '32', '女', ['看書', '旅遊','繪畫']) ] const server = http.createServer(function(req, res){ const query = url.parse(req.url, true) if ( query.pathname === '/' ) { fs.readFile('./index.htm', function(err, data) { if ( err !== null ) { return res.end('<h1>404 沒找到模版檔案!</h1>') } const strHtml = template.render(data.toString(), { "db": db }) res.end(strHtml) }) } else if ( query.pathname === '/add' ) { req.on('data', function(chunk) { const obj = querystring.parse(chunk.toString()) db.push(new human( obj['uname'], obj['age'], obj['sex'], obj['items'].split(','), )) }) res.writeHead(302, { 'location': `/` }) res.end() } else { return res.end('<h1>404 頁面沒找到!</h1>') } }) server.listen(8080, function(){ console.log('請訪問http://localhost:8080/,按Ctrl+C終止服務!') })
-
儲存所有檔案後,在
code/05_webForm/post_form
目錄下執行node app.js
命令,結果如下: