用 Express 製作簡易的留言版

之前我們使用原生 Node.js 製作了一個簡單的留言版應用程式, 現在讓我們把這個小練習用 Express 來改寫吧。

這篇部分程式碼和之前原生的版本是一樣的(如HTML), 有些細節在這篇就不再重複演示, 如有不夠清楚的地方, 可以搭配服用:用 Node.js 製作簡易的留言版

檔案結構

除了改寫 app.js 以外, 其他配置包含程式碼, 大部分都和之前 Node.js 原生版本一樣

1
2
3
4
5
6
7
8
— app.js
— views
  ∟ index.html
  ∟ post.html
  ∟ 404.html
— public
∟ lib
∟ bootstrap.css

app.js

  • 後端邏輯程式碼

views

  • HTML 檔案, 分別是首頁、發表留言頁、404警告頁

public

  • 靜態資源資料夾, 包含所有第三方套件、圖片、前端js檔、css檔, 這些在 HTML 標籤中, 如 <link> <script> <img> 所請求的資源

起手式

Express 服務基本配置, 並且配置首頁(index.html) 及發表留言頁(post.html) 路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const express = require('express')
const app = express()

const host = '127.0.0.1'
const port = 3000

app.get('/', function (req, res) {
res.send('首頁')
})
app.get('/post', function (req, res) {
res.send('留言頁')
})

app.listen(port, host, function () {
console.log(`app is runnig at ${host}:${port}`)
})

在 Express 中使用 art-template 模板引擎

art-template 模板引擎套件也有提供一種 Express 框架可使用的版本, 詳細配置請參考文件: art-template Express

安裝

1
2
npm install --save art-template
npm install --save express-art-template

express-art-template 是把 art-template 整合在 Express 中的套件。在 Express 中使用時, 不需要特別 require('art-template'), 但是必須要安裝, 因為 express-art-template 套件中有引入 art-template。

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const express = require('express');
const app = express();
const host = '127.0.0.1'
const port = 3000

// view engine setup (核心配置)
app.engine('html', require('express-art-template')); // ##

// routes
app.get('/', function (req, res) {
res.render('index.html')
})
app.get('/post', function (req, res) {
res.render('post.html')
})

app.listen(port, host, function () {
console.log(`app is runnig at ${host}:${port}`)
})
  • engine() 方法的第一個參數是在告訴模板引擎, 渲染 .html 附檔名的檔案時, 使用模板引擎渲染
  • Express 原生就為 res 物件提供一個方法 render, 但預設是無法使用的, 需要搭配模板引擎後才能使用
    • 參數: res.render('html模板檔名', 欲渲染的資料(型別為物件, 可選參數))
    • 第一個參數不可寫路徑, 僅需提供檔名, 模板引擎預設會到 views 資料夾中尋找該模板檔案。 因此建議開發者建立一個 views 資料夾, 然後將 html 檔案都放到該資料夾中
    • 如果想要修改預設的資料夾,可以使用
      1
      app.set('views', 新的資料夾名稱)

將資料帶入模板引擎

目前的程式碼只會回傳靜態的 index 頁面, 因此還需要使用模板引擎動態渲染留言的資料到 index.html 上。

宣告一個處理留言資料的物件, 先寫死兩個留言資料, 屬性有

  • name 留言者
  • message 留言內容
  • dateTime 留言時間
1
2
3
4
5
6
7
8
9
10
11
12
let comments = [
{
name: '王曉明',
message: '今天天氣不錯',
dateTime: '2019-08-09 13:00:00'
},
{
name: '王曉華',
message: '對阿',
dateTime: '2019-08-09 12:00:00'
}
]

將資料帶入模板引擎渲染

1
2
3
4
5
app.get('/post', function (req, res) {
res.render('post.html', {
comments: comments
})
})

處理發表留言

使用 get 方法發送留言請求

表單 HTML

1
2
3
4
5
6
7
8
9
10
11
<form action="/comment" method="get">
<div class="form-group">
<label for="input_name">你的大名</label>
<input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="請寫入你的姓名">
</div>
<div class="form-group">
<label for="textarea_message">留言內容</label>
<textarea class="form-control" name="message" id="textarea_message" cols="30" rows="10" required minlength="5" maxlength="20"></textarea>
</div>
<button type="submit" class="btn btn-primary">發表</button>
</form>

伺服器程式碼

1
2
3
4
5
6
7
app.get('/comment', function (req, res) {
// 在 Express 中可以直接使用 req.query 取得 GET 請求所夾帶的 query, 且已自動將它處理成物件格式
var newComment = req.query
newComment.dateTime = new Date().toLocaleString()
comments.unshift(newComment)
res.redirect('/')
})

原生的留言版練習中, 在使用者發表留言後作了以下處理

  • 設定狀態碼 302 告訴伺服器做臨時重新導向
  • 設定 Response Header 中的 Location 屬性, 告訴瀏覽器重新導向到哪裡
  • 結束響應

而 Express 為我們提供 res.redirect 方法(帶入一個參數, 該參數帶入欲重新導向的路徑), 只要需要使用一個方法, 就可以將上述所有步驟全部都搞定。

使用 post 方法發送留言請求

到此, 已經改寫完 Express 版的留言板, 現在試著來做一個小練習, 將發表留言從 GET 請求改為 POST 請求。

1
<form action="/comment" method="post">

GET 請求可以使用 query 夾帶資料, 傳送到伺服器, 而 POST 無法這麼做, POST 方法必須透過 Request Body 來夾帶資料做傳送。因此後端無法用 req.query 取得資料, 必須要做改寫。

修改程式碼

1
2
3
app.post('/comment', function (req, res) {
res.send('收到 POST 請求')
})

發起一個 POST 請求

按下發送按鈕後, 查看開發者工具的 Network, 可以看到這次的請求所夾帶的資料

接下來的問題是, 如何在 Express 中取得 POST 請求所夾帶的 Request Body?

取得 POST 請求體(Request Body)

在 Express 中預設是無法直接取得表單 POST 方法的 Request Body 的, 需要透過第三方套件 body-parser 實現。

body-parser 文件

安裝

1
npm install --save body-parser

配置

1
2
3
4
const bodyParser = require('body-parser)

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

接著就可以透過 res.body 取得 POST 方法所夾帶的 Request Body

1
2
3
4
5
6
app.post('/comment', function (req, res) {
var newComment = req.body
newComment.dateTime = new Date().toLocaleString()
cmds.unshift(newComment)
res.redirect('/')
})

DEMO

Github