用 Node.js 實作 server
const http = require('http') // 內建 http module
const server = http.createServer(handler)
function handler(req, res) {
console.log(req.url)
if (req.url === "/123") { // 在 URL 輸入 123 會得到 456
res.writeHead(200, {
'Content-Type': 'text/html' // 告訴瀏覽器要回傳的內容格式是 html,註解掉還是可以得到 html 格式的內容,因為 chrome 有作設定
})
res.write("<h1>hello</h1>")
}
if (req.url === "/redirect") {
res.writeHead(301, {
'Location': 'https://google.com'
})
}
res.write("hello") // 畫面上會出現 hello
res.end() // 把 response 丟回去
}
server.listen(5001)
- 去瀏覽器,URL 輸入 localhost: 5001,會得到 hello
- Node.js 會跳出
/favicon.ico
,代表這個 logo
- Express 的底層是 Node.js
Express
const express = require('express')
const app = express() // express 引入進來的東西是 function,去執行它就可以建立一個 app
const port = 5001
app.get('/', (req, res) => {
res.send('hello world')
}) // 第二個 cb 為代表怎麼去處理進來的 request
app.get('/sup', (req, res) => {
res.send('nail it') // 在 URL 輸入 localhost:5001/sup 會得到 nail it
})
app.listen(port, () => {
console.log(`hello world, listening on port ${port}`)
})
- 把各種 http 的 method (request 給誰處理、導到哪裡去) 直接包裝成函式 (Basic routing),像是
app.get()
、app.post()
、app.delete()
與之前用 PHP + Apache 相異的點
PHP + Apache
- 瀏覽器 -> Apache Server -> PHP -> Apache Server -> 瀏覽器
- 檔案結構會長得跟 URL 一樣
Express
- 瀏覽器 -> Express Server -> 瀏覽器
- URL 不會被檔案結構侷限住
Express 的基本架構與 MVC(Model View Controller)
流程
- request -> controller (coordinator) -> model (in charge of data)
- controller -> view (template) 呼叫模板,並把 data 塞進去,然後 view 就會有一個完整的 response 出來
- controller -> response
實作 todo list
前置作業
- 參考 官方文件 先安裝 template engines
npm install ejs
- 新增資料夾
views
,並在該資料夾下新增hello.ejs
- 回到上一層資料夾,去
index.js
裡面新增以下程式碼:
app.set('view engine', 'ejs') // ejs 為一種 template system,利用
app.get('/hello', (req, res) => {
res.render('hello') // 叫 Express 去 render views 底下 hello 這個檔案(副檔名不用填)
})
- 打開瀏覽器,輸入:http://localhost:5001/hello
,會得到 hello.ejs 這個檔案被 render 過的內容,若修改此檔案,只要按儲存,便可以重新整理網頁,得到新 render 的內容
什麼是 EJS
EJS is a template system. You define HTML pages in the EJS syntax and you specify where various data will go in the page. Then, your app combines data with the template and "renders" a complete HTML page where EJS takes your data and inserts it into the web page according to how you've defined the template. For example, you could have a table of dynamic data from a database and you want EJS to generate the table of data according to your display rules. It saves you from the drudgery of writing code to dynamically generate HTML based on data.
開始做 todo list
- 在
views
資料夾下新增todos.ejs
這個檔案,並輸入以下程式碼:
<h1>Todos</h1>
<ul>
<% for(let i = 0; i < todos.length; i++) { %>
<li><%= todos[i] %></li> <!--前面加等號,代表後面的東西要輸出-->
<% } %>
</ul>
- 到
index.js
輸入以下程式碼:
const todos = ['first todo', 'second todo', 'third todo']
app.get('/todos', (req, res) => {
res.render('todos', {
todos // ES6 如果 todos: todos (名稱一樣)可以只寫 todos,這段程式碼代表在檔案 todos.ejs 裡面的變數 todos 會是 todos 這個陣列
})
})
打開瀏覽器
到
index.js
輸入以下程式碼:
app.get('/todo/:id', (req, res) => { // 用冒號,代表為一個不確定的東西,是參數
const id = req.params.id // params 為 parameter 的意思,可以拿到網址列上面指定好的 id
const todo = todos[id]
res.render('todo', {
todo
})
})
- 在
views
資料夾下新增todo.ejs
這個檔案,並輸入以下程式碼:
<h1>Todo</h1>
<h2><%= todo %></h2>
- 打開瀏覽器:
重構專案
models (data)
- 新增
models
的資料夾,並在資料夾底下新增檔案todo.js
todo.js
裡面的內容輸入以下程式碼,處理資料並將資料包成函式:
const todos = [
'first todo', 'second todo', 'third todo'
]
const todoModel = {
getAll: () => {
return todos
},
get: (id) => {
return todos[id]
}
}
module.exports = todoModel
views
- 負責顯示
- 資料夾下有兩個檔案,分別為
todo.ejs
、todos.ejs
todo.ejs
:
<h1>Todo</h1>
<h2><%= todo %></h2>
todos.ejs
:
<h1>Todos</h1>
<ul>
<% for(let i = 0; i < todos.length; i++) { %>
<li><%= todos[i] %></li> <!--前面加等號,代表後面的東西要輸出-->
<% } %>
</ul>
controllers
- 新增
controllers
資料夾,底下新增檔案todo.js
- 負責去 model 拿資料,然後 render 出來
const todoModel = require('../models/todo')
const todoController = {
getAll: (req, res) => {
const todos = todoModel.getAll()
res.render('todos', { // 交給 view engine 去作
todos
})
},
get: (req, res) => {
const id = req.params.id
const todo = todoModel.get(id)
res.render('todo', {
todo
})
}
}
module.exports = todoController
路由
- index.js:
const express = require('express')
const app = express() // express 引入進來的東西是 function,去執行它就可以建立一個 app
const port = 5001
const todoController = require('./controllers/todo'
)
app.set('view engine', 'ejs')
const todos = ['first todo', 'second todo', 'third todo']
app.get('/todos', todoController.getAll)
app.get('/todos/:id', todoController.get)
app.listen(port, () => {
console.log(`hello world, listening on port ${port}`)
})
- 還可更進一步視專案大小作簡化