node學習二 (url替裆、http校辩、事件循環(huán)和回調(diào)函數(shù))

http模塊

  1. 創(chuàng)建服務器兩種方式
// 方式一 http.createServer([requestListener])
/*
 * [requestListener(req, res)] 用戶請求后回調(diào)函數(shù),有兩個參數(shù)辆童,req請求宜咒;res響應
 * @return http.Server 返回一個http.Server實例
 */
var server = http.createServer((req, res) => {
    res.writeHeader(200,{'Content-Type':'text/plain'});
    res.end('hello world');
})
 // 方式二 new http.Server()
 var server = new http.Server();
 server.on('request', (req, res){
    res.writeHeader(200,{'Content-Type':'text/plain'});
        res.end('hello world');
 })

采用上面的方式并不能創(chuàng)建一個完成的服務器,還必須監(jiān)聽對應的端口把鉴,比如采用下面這種方式故黑。

// 表示引入http模塊
const http = require('http');

// 創(chuàng)建一個http服務
/*
   request: 獲取url傳過來的信息  請求頭
   response: 像瀏覽器響應信息  響應頭
*/
http.createServer(function(request,response){
    // 設置響應頭
    response.writeHead(200,{'Content-Type': 'text/plain'});

    response.write('1111');// 像頁面返回的內(nèi)容
    response.write('222');
    // 像瀏覽器輸出一句話 并結束響應
    response.end('1123122'); // 

}).listen(8081);// 端口

為啥要監(jiān)聽端口(listen(8080))?

端口的功能
一臺擁有IP地址的主機可以提供許多服務庭砍,比如Web服務场晶、FTP服務、SMTP服務等怠缸,這些服務完全可以通過1個IP地址來實現(xiàn)峰搪。那么,主機是怎樣區(qū)分不同的網(wǎng)絡服務呢凯旭?顯然不能只靠IP地址概耻,因為IP 地址與網(wǎng)絡服務的關系是一對多的關系使套。實際上是通過“IP地址+端口號”來區(qū) 分不同的服務的。

客戶端通常對它所使用的端口號并不關心鞠柄,只需保證該端口號在本機上是唯一的就可以了侦高。客戶端口號又稱作臨時端口號(即存在時間很短暫)厌杜。這是因為它通常只是在用戶運行該客戶程序時才存在奉呛,而服務器則只要主機開著的,其服務就運行夯尽。

簡單理解:IP就是一個電腦節(jié)點的網(wǎng)絡物理地址瞧壮,就像你的家住的那個地址;端口是該計算機邏輯通訊接口匙握,不同的應用程序用不同的端口咆槽,就像你家里的各個不同的房間,臥室用來睡覺圈纺,餐廳用來吃飯秦忿。
理解為 node啟動一個服務就是將本機當做了服務器,所以它的ip地址是127.0.0.1 蛾娶,其中端口8080端口里面是提供你要的服務灯谣。

Url模塊

在上面創(chuàng)建的那個服務器里面,頁面所有的請求都會執(zhí)行createServer中傳入的方法蛔琅。但是不同的請求胎许,需要做不同的處理,所以我們需求判斷請求路徑罗售,以便我們做出不同的響應辜窑。

我們可以很簡單的獲取到請求的url,但有數(shù)據(jù)提交上來的url是十分復雜和不確定的。很不利于編寫業(yè)務邏輯莽囤。所以我們就要將url拆分成我們能用的數(shù)據(jù)谬擦。node的url模塊就是幫助我們對提交上來的url進行解析處理

常用方法:

parse(urlStr,queryString,AnalysisHost)

解析url切距,返回一個url屬性對象
urlStr: 要解析的url地址
queryString: 解析出來的query是字符串還是查詢對象朽缎,true是對象 false是字符串
AnalysisHost: 是否要解析出來主機名

實例代碼

  var url = require('url')
  var obj = url.parse('http://www.baidu.com/vdsa?ie=utf-8&word=sad',true,true)
  console.log(obj);

結果:


Url組成部分:

  • protocol:url的通信協(xié)議(http/https)
  • slashes:如果協(xié)議protocol冒號后跟的是兩個斜杠字符(/),那么值為true
  • auth:URL的用戶名與密碼部分
  • host:url的主機名 “baidu.com”
  • port: 端口號
  • hostname: hostname是host屬性排除端口port之后的小寫的主機名部分
  • hash:哈希#后面字符串包括#
  • search:URL的查詢字符串部分,包括開頭的問號字符(谜悟?)
  • query: 不包含問號(话肖?)的search字符串
  • pathname:URL的整個路徑部分。跟在host后面葡幸,截止問號(最筒?)或者哈希字符(#)分隔
  • path:由pathname與search組成的串接,不包含hash字符后面的東西
  • href:解析后的完整的URL字符串,protocol和host都會被轉換成小寫蔚叨。

事件循環(huán)和回調(diào)函數(shù)

我們都知道床蜘,不同的請求對應的Content-type是不一樣的辙培,比如一個頁面的加載html和css的Content-type是不一樣的。

文件目錄為:


image.png

mime.json文件的內(nèi)容為:

{ ".323":"text/h323" ,
  ".3gp":"video/3gpp" ,
  ".asc":"text/plain" ,
  ".htm":"text/html" ,
  ".html":"text/html" 
.....
}

我們現(xiàn)在通過getTypeFile方法來獲取不同文件后綴對應的Content-type邢锯。

const http = require('http');
const fs = require('fs');
const path = require('path');
const URL = require('url');
const utils = require('./utils/getType');
const EventEmitter = require('./utils/Listener');
http.createServer(function(request,response){
    const pathname = request.url;
    let extname = path.extname(URL.parse(pathname).pathname); // 獲取文件后綴名
 if(pathname !== '/favicon.ico'){
         返回對應的頁面
        response.writeHead(200,{
            'Content-Type': `${utils.getTypeFile(extname)};charset='utf-8'`
         });
            fs.readFile('./static/'+URL.parse(pathname).pathname,    (err,data)=> {
                    response.end(data);
                }
            })
    }else {
        response.end()
    }        
}).listen(8081)
console.log('服務啟動了')

getTypeFile方法為:

exports.getTypeFile = function(exname){
    const obj = fs.readFileSync('./mime.json').toString();
    return JSON.parse(obj)[exname];
}

當getTypeFile是一個同步方法的時候扬蕊,上面的代碼是沒有任何問題的。但是如果使用fs.readFile這個異步方法的時候就會出現(xiàn)問題丹擎。因為外面得不到返回的值尾抑。這里readFildSync是一個同步的方式 ,如果采用異步的方法 readFile 在app.js 如何得到想要值呢 蒂培。

一般解決這種問題的有事件循環(huán)再愈、和回調(diào)函數(shù)的解決方式。

回調(diào)函數(shù)

// app.js
const utils = require('./utils/getType');
...code
utils.getTypeFild(exname,function(str){
    response.writeHead(200,{
            'Content-Type': `${str};charset='utf-8'`
        });
    ... code    
})

// getType.js
exports.getTypeFile = function(exname,callback){
    fs.readFile('./mime.json',(err,data) =>{
        callback(data.toString);
    })
}

通過在給getTypeFile傳入一個回調(diào)方法护戳,在readFile執(zhí)行完成后翎冲,在執(zhí)行回調(diào)方法。Node 使用了大量的回調(diào)函數(shù)灸异,Node 所有 API 都支持回調(diào)函數(shù)

事件驅動

event 模塊只提供了一個對象 events.EventEmitter,
核心就是事件觸發(fā)和事件監(jiān)聽功能府适,原生使用原理類似于觀察者模式。

創(chuàng)建 eventEmitter 對象

// 引入 events 模塊
var events = require('events');
// 創(chuàng)建 eventEmitter 對象
var eventEmitter = new events.EventEmitter();

以下程序綁定事件處理程序:

// 綁定事件及事件的處理程序
eventEmitter.on('eventName', eventHandler);

我們可以通過程序觸發(fā)事件:

// 觸發(fā)事件
eventEmitter.emit('eventName');

所以如果采用事件驅動驅動的方式我們的第二種實現(xiàn)方式為:

1. getType.js
const fs = require('fs');
const events= = require('events');
const EventEmitter = new events.EventEmitter();// 實例化事件對象
exports.getTypeFile = function(exname){
    fs.readFile('./mime.json',(err,data) =>{
       EventEmitter.emit('exname', data.toString()); // 發(fā)送一個名為exname 的廣播
    })
}

2. app.js
const fs = require('fs');
const events= = require('events');
const EventEmitter = new events.EventEmitter();
...code

if(pathname !== '/favicon.ico'){
        // 接受一個名為 exname的廣播
        EventEmitter.on('exname',(data) =>{
            response.writeHead(200,{
            'Content-Type': `${data};charset='utf-8'`
            });
            ...code;
        })        
}

這里有一個錯誤的地方是肺樟,兩個文件中都通過new events.EventEmitter()來生成了一個EventEmitter對象檐春,盡管他們兩個的名字一樣,但是他們兩個是不同的實例么伯。所以會發(fā)現(xiàn)在app.js中并沒有接受到一個名為 exname的廣播疟暖。

為了保證是一個EventEmitter對象,我們采用這種方法田柔,將app.js俐巴、和getType.js中的

const events= = require('events');
const EventEmitter = new events.EventEmitter();// 實例化事件對象

替換為

const EventEmitter = require('./Listener');

// Listenser.js
const events = require('events');
const EventEmitter = new events.EventEmitter();
module.exports = EventEmitter;

這樣兩個文件使用的就是同一個EventEmitter

參考文章:

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市硬爆,隨后出現(xiàn)的幾起案子欣舵,更是在濱河造成了極大的恐慌,老刑警劉巖缀磕,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缘圈,死亡現(xiàn)場離奇詭異,居然都是意外死亡袜蚕,警方通過查閱死者的電腦和手機糟把,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牲剃,“玉大人遣疯,你說我怎么就攤上這事≡涓担” “怎么了缠犀?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵数苫,是天一觀的道長。 經(jīng)常有香客問我辨液,道長文判,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任室梅,我火速辦了婚禮戏仓,結果婚禮上,老公的妹妹穿的比我還像新娘亡鼠。我一直安慰自己赏殃,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布间涵。 她就那樣靜靜地躺著仁热,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勾哩。 梳的紋絲不亂的頭發(fā)上抗蠢,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音思劳,去河邊找鬼迅矛。 笑死,一個胖子當著我的面吹牛潜叛,可吹牛的內(nèi)容都是我干的秽褒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼威兜,長吁一口氣:“原來是場噩夢啊……” “哼销斟!你這毒婦竟也來了?” 一聲冷哼從身側響起椒舵,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蚂踊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后笔宿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體犁钟,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年措伐,在試婚紗的時候發(fā)現(xiàn)自己被綠了特纤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片军俊。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡侥加,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出粪躬,到底是詐尸還是另有隱情担败,我是刑警寧澤昔穴,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站提前,受9級特大地震影響吗货,放射性物質發(fā)生泄漏。R本人自食惡果不足惜狈网,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一宙搬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拓哺,春花似錦勇垛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至烤礁,卻和暖如春讼积,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脚仔。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工勤众, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鲤脏。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓决摧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凑兰。 傳聞我的和親對象是個殘疾皇子掌桩,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 電梯上已經(jīng)沒有人了,但它還在播報著姑食,請握緊扶手波岛,注意腳下,不要倚靠扶梯音半。有人來了则拷,地鐵口又熱鬧了。有教訓娃娃不要亂...
    沒有心思閱讀 143評論 0 0
  • 圖解計算機 由上圖可知:計算機系統(tǒng)由硬件系統(tǒng)和軟件系統(tǒng)組成 1.計算機硬件系統(tǒng)從邏輯上主要由運算器曹鸠、控制器煌茬、存儲器...
    莫戀初閱讀 833評論 0 1
  • 林深時見鹿,海藍時見鯨彻桃,夢醒時見你 可實際:林深時霧起坛善,海藍時浪涌,夢醒時夜續(xù) 未見鹿,未見鯨眠屎,亦未見你剔交。 但:鹿...
    小丑豹閱讀 153評論 0 0
  • 胡璨作文集2017-083【暑假作文57】海底小縱隊2祁門縣閶江小學302班 胡璨2017年8月26日 星期六 晴...
    胡璨HUCAN閱讀 869評論 0 6
  • 姓名 :趙樂坤 圖片發(fā)自簡書App 企業(yè)名稱:阿里米丁節(jié)能科技(蘇州)有限公司 組別 謙虛二組 【日精進打卡第71...