其他章節請看:
簡易版 Apache
我們用 node 來實現一個簡易版的 Apache:提供靜態資源訪問的能力。
實現
直接上程式碼。
- demo
- static // 靜態資原始檔夾
- index.html // 主頁
- 1.jpg
- 1.css
- 1.js
- index.js // 入口檔案
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="1.css">
</head>
<body>
<p>歡迎來到首頁</p>
<img src="1.jpg" alt="">
<section></section>
<script src='1.js'></script>
</body>
</html>
1.js 和 1.css:
document.querySelector('section').innerHTML = '我來自js' // js
body{color:red} // css
index.js(入口檔案):
const http = require('http')
const fs = require('fs')
const server = http.createServer()
const requestListener = (req, res) => {
const url = req.url
// 如果url是 '/',則返回主頁
if(url === '/'){
fs.readFile('./static/index.html', (err, data) => {
if (err) throw err;
res.end(data)
});
return
}
// 如果url不是 '/',則返回資源(找不到資源則報 404)
fs.readFile('./static/' + url, (err, data) => {
if (err) {
res.writeHead(404, {'Content-type':'text/html;charset=utf8'})
res.end('沒有找到對應的資源')
}
res.end(data)
})
}
server.on('request', requestListener)
server.listen('3000', () => {
console.log('伺服器已啟動')
})
啟動伺服器:
$ node index
檢驗伺服器是否能提供靜態資源訪問的能力。
1. 瀏覽器輸入 http://localhost:3000/1.css
頁面顯示:body{color:red}
2. 瀏覽器輸入 http://localhost:3000/1.js
頁面顯示:document.querySelector('section').innerHTML = '鎴戞潵鑷猨s'(未指定編碼,所以中文亂碼。不礙事)
3. 瀏覽器輸入 http://localhost:3000/1.jpg
頁面顯示:1.jpg(正常顯示圖片)
3 種靜態資源都能正常響應。
訪問主頁:
瀏覽器輸入:http://localhost:3000/index.html 或 http://localhost:3000/
頁面顯示:
歡迎來到首頁
圖片
我來自js
主頁和其中的圖片、css 以及 js 配合的非常完美。
注:中文亂碼的問題沒有出現。因為我們在 html 頁面中 使用了 <meta charset="utf-8">
來指定編碼。
通常訪問不存在的資源會返回 404。請看:
瀏覽器輸入:http://localhost:3000/2.css
頁面顯示:
沒有找到對應的資源
擴充套件
至此,我們的簡易版 apache 其實已經大功告成。在此基礎之上,我們再擴充套件一下。
我的伺服器我做主
理解這一點很重要:這個伺服器完全由我們做主。
現在所有的請求都會進入 requestListener() 方法,如果 url 是 '/',伺服器就返回主頁(index.html),否則就去 static 資料夾中讀取相應的資源,如果沒有找到對應的資源,就做 404 的處理。假如 requestListener() 是一個空方法,則說明我們的伺服器不提供任何服務。
所有的請求都是 url
不要把 http://localhost:3000/1.css
中的 1.css 當成檔案路徑,而要當成 url,因為所有的請求都是 url。請看示例:
const requestListener = (req, res) => {
...
if(url.endsWith('.myCss')){
url = url.replace('.myCss', '.css') // url 得宣告成 let
}
fs.readFile('./static/' + url, (err, data) => { // {1}
...
})
}
在 index.js 的 fs.readFile('./static/'
(行{1}) 上面增加三行程式碼。
瀏覽器輸入 http://localhost:3000/1.myCss
頁面顯示:body{color:red}
現在給伺服器傳送請求 http://localhost:3000/1.myCss
,伺服器也會返回 1.css 檔案的內容。有些網站的 url 設計的非常優雅。請看:
http://product.dangdang.com/29200520.html
// 更優雅
https://www.douban.com/group/topic/214827461/
重定向
未登入的狀態去訪問頁面,通常會被重定向到首頁。我們來模擬一下:
if(url.endsWith('.myCss')){
url = url.replace('.myCss', '.css')
res.writeHead(302, {'Location':'/'}) // {1}
// 行{1} 等價於下面兩行
// res.statusCode = '302'
// res.setHeader('Location', '/')
}
在 index.js 中增加 res.writeHead(302, {'Location':'/'})
(行{1}),瀏覽器輸入 http://localhost:3000/1.myCss
,頁面會重定向到主頁。
注:沒有後端開發經驗的學習 node 會比較吃力。比如重定向,我們想到的可能是通過呼叫一個重定向的方法來實現,而 node 寫起來更底層。
302 是臨時重定向。301 是永久重定向。請看示例:
// 臨時重定向
Request URL: http://localhost:3000/1.myCss
Request Method: GET
Status Code: 302 Found
Request URL: http://localhost:3000/1.myCss
Request Method: GET
Status Code: 302 Found
// 永久重定向
Request URL: http://localhost:3000/1.myCss
Request Method: GET
Status Code: 301 Moved Permanently
Request URL: http://localhost:3000/1.myCss
Request Method: GET
Status Code: 301 Moved Permanently (from disk cache) // {1}
臨時重定向,瀏覽器每次都會去伺服器那裡;而永久重定向,第二次就不會去伺服器那裡,而是直接在瀏覽器端重定向過去(行{1})
自動重啟服務
每次修改入口檔案,都需要重新啟動伺服器(執行 node index
),非常麻煩。
可以通過 nodemon 來幫助我們自動重啟服務。
// 全域性安裝 nodemon。
$ npm install --global nodemon
// 一定要全域性安裝 nodemon。否則執行 nodemon -v 會報錯。
$ nodemon -v
// 執行入口檔案。
$ nodemon index // {1}
使用 nodemon 非常簡單。通過 npm 全域性安裝後,用 nodemon 代替 node(行{1})執行入口檔案即可。
注:筆者還嘗試了 supervisor,感覺沒有 nodemon 好用。比如我輸入 let a =
(處在一個語法錯誤的狀態)然後儲存,supervisor 會退出服務,而 nodemon 只是報錯,仍會繼續監聽。
其他章節請看: