一棚品、使用 Node 構(gòu)建 web 應(yīng)用
- PHP是后端的網(wǎng)站開發(fā)語言蚜迅,PHP 開發(fā)出來的網(wǎng)站捎泻,可以通過 Apache 服務(wù)器托管運行起來;
- Node中诡曙,可以使用 Javascript 編寫后端網(wǎng)站臀叙,沒有類似于 Apache 這樣的服務(wù)器軟件,來提供對應(yīng)的網(wǎng)站服務(wù)价卤。所以需要手動編寫一個劝萤。
二、B/S 交互模型
什么是B/S:特指基于 瀏覽器(Browser) 和 服務(wù)器(Server) 這種交互形式慎璧;
- 什么是服務(wù)器:在網(wǎng)絡(luò)節(jié)點中床嫌,專門對外提供資源服務(wù)的一臺電腦;
- 什么是客戶端:在網(wǎng)絡(luò)節(jié)點中炸卑,專門用來消費服務(wù)的一臺電腦既鞠;
-
HTTP 協(xié)議的通信模型:請求 - 處理 - 響應(yīng)的過程煤傍;
- 請求:由客戶端發(fā)起請求盖文;
- 處理:由服務(wù)器端處理請求;
- 響應(yīng):服務(wù)器端把處理的結(jié)果蚯姆,通過網(wǎng)絡(luò)發(fā)送給客戶端五续;
- 什么是靜態(tài)資源:服務(wù)器端只需要讀取并直接發(fā)送給客戶端、不需要進(jìn)一步處理的資源龄恋,叫做靜態(tài)資源疙驾;
- 什么是動態(tài)資源:服務(wù)器端沒有現(xiàn)成的資源,需要服務(wù)器端動態(tài)生成的資源郭毕,叫做動態(tài)資源它碎;
三、實現(xiàn)一個類似于Apache的 靜態(tài)資源服務(wù)器
使用http核心模塊,創(chuàng)建最基本的web服務(wù)器
1. 創(chuàng)建最基本的web服務(wù)器
- 導(dǎo)入http模塊:const http = require("http")扳肛;
- 創(chuàng)建服務(wù)器:使用 const server = http.createServer() 創(chuàng)建服務(wù)器傻挂;
- 綁定監(jiān)聽事件:通過 server.on('request', function(req, res) { 請求的處理函數(shù) }) 綁定事件 并 指定 處理函數(shù);
- 啟動服務(wù)器:通過 server.listen(端口, IP地址, 啟動成功的回調(diào)函數(shù)) 來啟動服務(wù)器挖息;
- res.end() 向客戶端發(fā)送內(nèi)容
// 導(dǎo)入http核心模塊
const http = require("http");
// 創(chuàng)建服務(wù)器
const server = http.createServer();
// 綁定request事件,監(jiān)聽客戶端請求
server.on("request", function(req, res) {
// end方法向客戶端發(fā)送內(nèi)容
res.end("hello world");
});
// 啟動服務(wù)器
server.listen(3000, "127.0.0.1", function() {
console.log("server running at http://127.0.0.1:3000");
});
2. 防止響應(yīng)內(nèi)容中文亂碼問題
- 通過 設(shè)置響應(yīng)報文頭的 Content-Type金拒,來指定響應(yīng)內(nèi)容的編碼類型,從而防止亂碼:
res.writeHeader(200, {
'Content-Type': 'text/plain; charset=utf-8'
})
3. 根據(jù)不同的URL返回不同的文本內(nèi)容
- 使用 req.url 獲取客戶端請求的URL地址
- res.writeHeader() 指定編碼格式
server.on('request', function(req, res) {
const url = req.url
// 防止中文亂碼
res.writeHeader(200, {
// text/plain 和 text/html的區(qū)別: plain表示普通的文本字符串套腹; html 表示以 HTMl 標(biāo)簽的形式去解析服務(wù)器返回的內(nèi)容
// image/jpg绪抛、image/gif、image/png
'Content-Type': 'text/plain; charset=utf-8'
})
if (url === '/' || url === '/views/index.html') {
res.end('首頁')
} else if (url === '/views/movie.html') {
res.end('電影')
} else if (url === '/views/about.html') {
res.end('關(guān)于')
} else {
res.end('請求的內(nèi)容不存在电禀!')
}
})
4. 根據(jù)不同的URL返回不同的HTML頁面
- 主要思路:使用 fs 模塊 讀取URL對應(yīng)的HTML頁面內(nèi)容幢码,并使用 res.end() 響應(yīng)給客戶端即可;
const http = require('http')
const fs = require('fs')
const path = require('path')
const server = http.createServer()
server.on('request', function(req, res) {
const url = req.url
// TODO: 判斷請求的URL地址鞭呕,返回對應(yīng)的HTML頁面內(nèi)容
if (url === '/' || url === '/views/index.html') {
// 返回首頁頁面
// 1. 使用 fs 模塊蛤育,讀取 首頁文件
// 2. 把讀取到的首頁,通過 res.end 返回即可
fs.readFile(path.join(__dirname, './views/index.html'), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
} else if (url === '/views/movie.html') {
// 返回電影頁面
fs.readFile(path.join(__dirname, './views/movie.html'), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
} else if (url === '/views/about.html') {
// 返回關(guān)于頁面
fs.readFile(path.join(__dirname, './views/about.html'), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
} else if (url === '/css/1.css') {
// 讀取樣式表
fs.readFile(path.join(__dirname, '/css/1.css'), (err, buf) => {
if (err) return res.end('404. Not found.')
res.end(buf)
})
} else if (url === '/js/1.js') {
// 讀取 JS 文件
fs.readFile(path.join(__dirname, '/js/1.js'), (err, buf) => {
if (err) return res.end('404. Not found.')
res.end(buf)
})
}
})
5. 處理并返回css樣式表
6. 處理并返回Javascript文件
7. 優(yōu)化
// res.end() 方法葫松,接收兩種類型的數(shù)據(jù) String 瓦糕,二進(jìn)制類型的數(shù)據(jù)
// 網(wǎng)絡(luò)傳輸?shù)臅r候是二進(jìn)制數(shù)據(jù),所以可以省略第二個參數(shù)腋么,dataStr為二進(jìn)制數(shù)據(jù)
// 直接給res.end()方法傳入二進(jìn)制數(shù)據(jù)的話咕娄,就省了一步轉(zhuǎn)碼。
fs.readFile(path.join(__dirname, './views/about.html'), (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
客戶端請求任何資源珊擂,服務(wù)器處理后客戶端才能拿到
監(jiān)聽請求代碼可以優(yōu)化為:
server.on('request', function(req, res) {
const url = req.url
// TODO: 判斷請求的URL地址圣勒,返回對應(yīng)的HTML頁面內(nèi)容
if (url === '/' || url === '/views/index.html') {
// 返回首頁頁面
// 1. 使用 fs 模塊,讀取 首頁文件
// 2. 把讀取到的首頁摧扇,通過 res.end 返回即可
fs.readFile(path.join(__dirname, url), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
} else if (url === '/views/movie.html') {
// 返回電影頁面
fs.readFile(path.join(__dirname, url), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
} else if (url === '/views/about.html') {
// 返回關(guān)于頁面
fs.readFile(path.join(__dirname, url), 'utf-8', (err, dataStr) => {
if (err) return res.end('404. Not found.')
res.end(dataStr)
})
} else if (url === '/css/1.css') {
// 讀取樣式表
fs.readFile(path.join(__dirname, url), (err, buf) => {
if (err) return res.end('404. Not found.')
res.end(buf)
})
} else if (url === '/js/1.js') {
// 讀取 JS 文件
fs.readFile(path.join(__dirname, url), (err, buf) => {
if (err) return res.end('404. Not found.')
res.end(buf)
})
}
})
進(jìn)一步優(yōu)化, 去掉重復(fù)代碼:
server.on('request', function(req, res) {
let url = req.url
// TODO: 判斷請求的URL地址圣贸,返回對應(yīng)的HTML頁面內(nèi)容
// 單獨處理根目錄
if (url === '/') url = '/views/index.html'
fs.readFile(path.join(__dirname, url), (err, buf) => {
if (err) return res.end('404. Not found.')
res.end(buf)
})
})