(二)用node.js內(nèi)置模塊,模擬搭建簡單服務器(靜態(tài)資源文件請求的處理);
明確:NODE是用來開發(fā)后臺,服務器端;
首先要知道服務器端都需要處理的事情 (一般可大致分以下四個)
- 在服務器上創(chuàng)建一個服務(監(jiān)聽一個端口號)
- 接收(解析)客戶端的請求信息
- 找到客戶端需要的資源文件中的源代碼
- 把源代碼返回
用到最基本的三個內(nèi)置模塊:HTTP、URL、FS
HTTP
這個模塊主要用于創(chuàng)建服務、監(jiān)聽端口、接收請求、返回內(nèi)容的管理
- http.createServer : 創(chuàng)建一個服務,創(chuàng)建出來的服務默認遵循的是HTTP傳輸協(xié)議
- ...
URL
這個模塊主要用來解析URL地址的
- url.parse : 解析一個完整的URL(也可以不完整)中的每一項的
- url...
FS
提供一些方法,供開發(fā)者進行I/O的操作
- fs.readFileSync([pathname]):同步讀取指定文件中的內(nèi)容
- fs.readFile([pathname],[callback]):異步讀取指定文件中的內(nèi)容
舉個通俗易的例子幫助理解同步讀取和異步讀取:
例如小明準備開始讀一本書《紅樓夢》,小明可能分兩種方式把這本書讀完:
- 在讀這本書的時候,小明規(guī)定自己不能走神,除了讀書什么都不能做,于是三天不吃不喝不睡不上廁所啥也不干的情況下,最后小明終于讀完了《紅樓夢》,讀完一瞬間小明 game over了;
- 在讀紅樓夢期間,小明決定每天看兩個小時,期間正常吃飯睡覺打豆豆,最終花了一個月讀完并且能倒背如流,然后準備開始讀《三國演義》;
方法**1 就類似是同步讀取書中的內(nèi)容,即 fs.readFileSync([pathname]):
方法2 **就類似是異步讀取書中的內(nèi)容,即
fs.readFile([pathname],[callback])
此處的callback函數(shù) 就是讀完《紅樓夢》開始讀《三國》的動作
同步(sync): 一次就干一件事
異步(async): 干這件事的期間,下件事可以同時做
簡單模擬過程
var http = require('http'),
url = require('url'),
fs = require('fs');
var server = http.createServer(function (req, res) {
console.log('ok');
})
server.listen(8080,function () {
console.log('server is success,listening on 8080 port!');
// 當服務創(chuàng)建成功,并且端口號監(jiān)聽成功后,就會執(zhí)行這個回調(diào)函數(shù),一般會在這里面輸出一句話,提示創(chuàng)建成功 (此回調(diào)也可以不寫)不寫便不提示沒影響;
})
在瀏覽器中輸入以上地址向服務器發(fā)送請求:
在終端中顯示回調(diào)函數(shù)中自定義的語句,并且在瀏覽器中輸入地址發(fā)送請求后出現(xiàn)ok ,便說明已經(jīng)能與服務器建立連接;
建立連接成功后在服務器目錄下添加index.html , css/index.css和js/index.js文件, 并在里面隨意編寫一些內(nèi)容
需求是瀏覽器輸入地址發(fā)送請求后獲取到服務器端中的html、css及js文件;
//自行創(chuàng)建:(本例如下)
//index.html
<body>
<div> 一切美好事物從 'Hello World!'開始 </div>
</body>
// css/index.css
body{
color: #fff;
}
// js/index.js
document.body.style.background = 'green';
//服務器端jiao'beserver1.js
var http = require('http'),
url = require('url'),
fs = require('fs');
var server = http.createServer(function (req, res) {
console.log('ok');
var urlObj = url.parse(req.url,true),
pathname = urlObj.pathname,
query = urlObj.query;
if(pathname === '/index.html'){
// 客戶端想要請求的就index.html,我們需要獲取這個文件中的源代碼(I/O),并且把源代碼返回
var conFile = fs.readFileSync('./index.html')
res.write(conFile);
res.end();
}
if(pathname === '/css/index.css'){
var conFile = fs.readFileSync('./css/index.css')
res.end(conFile); //可以寫一起
}
if(pathname === '/js/index.js'){
var conFile = fs.readFileSync('./js/index.js')
res.end(conFile);
}
})
server.listen(8080,function () {
console.log('server is success,listening on 8080 port!');
})
此時瀏覽器便會從服務器得到相關數(shù)據(jù),瀏覽器通過引擎渲染后顯示以下結(jié)果:
但以上的server1.js代碼存在以下問題還需要進一步優(yōu)化:
- 同時需要獲取更多個靜態(tài)資源(100個html)文件時,就不能用if逐個判斷了;
- 在客戶端向我們的服務發(fā)送請求的時候,谷歌瀏覽器會默認請求一個圖片'favicon.ico',但是我們的服務器上是沒有這張圖片;如果報錯會影響之后的數(shù)據(jù)請求;
- IE中不能渲染css文件的問題;
優(yōu)化代碼如下:
var http = require('http'),
url = require('url'),
fs = require('fs');
var server = http.createServer(function (req,res) {
var urlObj = url.parse(req.url,true),
pathname = urlObj.pathname,
query = urlObj.query;
/*
* 靜態(tài)資源文件請求處理(HTML /CSS / JS / IMG / (PNG/JPG/GIF)/TXT...)
* 所有的靜態(tài)資源文件都有一個共同的特征:都有后綴名,后綴名是由字母和數(shù)字組成的
* 分析規(guī)律得到,服務器端需要查找文件的路徑地址只是在pathname前面加一個點即可;
* 在IE中的問題 :服務器端返回給客戶端的都是字符串格式的數(shù)據(jù)不管是HTML/CSS/JS/....),
對于谷歌瀏覽器來說,它比較智能,會自動識別當前代碼是什么類型的代碼,然后進行解析和渲染,但是IE這點不算智能,
不能識別具體的文件類型,都當成字符串了;
例:去商店買鹽,面粉,蘇打 三個白色的 google比較聰明能分辨各自是什么, ie分辨不出來只能在袋子上貼上標簽;
* 解決方案: 需要我們在返回數(shù)據(jù)給客戶端的時候,制定當前文件的MIME類型,告訴IE是什么類型即可
* MIME:
* HTML - > text/html
* CSS - > text/css
* JS -> text/javascript
* PNG -> text/png
* .....
* */
var reg = /\.([0-9a-zA-Z]+)/i;
if(reg.test(pathname)){
var conFile = null,
status = 200;
try {
conFile = fs.readFileSync('.'+pathname)
}catch(e){
conFile = 'not found~';
status = 404;
}
// 根據(jù)當前請求資源文件的后綴名,計算出文件的MIME類型
var suffix = reg.exec(pathname)[1].toUpperCase(),
suffixMIME = 'text/plain'; //默認是純字符串文本
switch(suffix){ // 根據(jù)具體項目需求添加
case 'HTML':
suffixMIME = 'text/html';
break;
case 'CSS':
suffixMIME = 'text/css';
break;
case 'JS':
suffixMIME = 'text/javascript';
break;
}
//在返回數(shù)據(jù)內(nèi)容之前制定MIME類型 (重寫響應頭)
res.writeHead(status,{
'content-type':suffixMIME + ';charset=utf-8;'
});
res.end(conFile)
}
})
server.listen(8080,function () {
console.log('server is success,lisening on 8080 port!');
});
test:
http://localhost:8080/index.html
http://本機IP:8080/index.html
在PC瀏覽器中地址欄輸入以上test;頁面如下說明test ok!
同局域網(wǎng)環(huán)境下手機 test Ok!
差不多就這樣,如有異議,歡迎指正;
來碗湯,壓壓驚~~~
“要得到你必須付出,要付出你還要學會堅持,如果你真的覺得很難,那你就放棄,但是你放棄了就不要抱怨,我覺得人生就是這樣,世界真的是平衡的,每個人都是通過自己的努力,去決定自己生活的樣子” ---- 何炅