使用 Node.js 搭建 Web 服務(wù)器

一 Web服務(wù)器

1. Web服務(wù)器的功能

1). 接收http請(qǐng)求 ( GET, POST) restful(DELETE, PUT, PATCH)

2). 處理HTTP請(qǐng)求 (自己處理, 或請(qǐng)求別的程序處理)
做出響應(yīng) (返回頁(yè)面, 文件, 各類(lèi)數(shù)據(jù)等)

2. 常見(jiàn)的Web架構(gòu)

1). Nginx/Apache: 負(fù)責(zé)接受HTTP請(qǐng)求, 確定誰(shuí)來(lái)處理請(qǐng)求, 并返回請(qǐng)求的結(jié)果

  1. php-fpm/php模塊 : 處理分配給自己的請(qǐng)求, 并將處理結(jié)果返回給分配者
3. 常見(jiàn)的請(qǐng)求種類(lèi)

1). 請(qǐng)求文件: 包括靜態(tài)文件(網(wǎng)頁(yè), 圖片嗎前端JavaScript文件, css文件...), 及由程序處理得到的文件

2). 完成指定的操作: 如登錄, 獲取特定數(shù)據(jù)等

二 Node.js 的Web服務(wù)器

特性:
1). 不依賴(lài)其他特性的Web服務(wù)軟件 (如 Apache, Nginx, IIS...)
2). Node.js代碼處理請(qǐng)求的邏輯
3). Node.js代碼負(fù)責(zé)Web服務(wù)器的各種 "配置"

1. 使用Node.js的核心模塊http搭建Web服務(wù)器

1). 創(chuàng)建web.js

//  web.js
//  引入http模塊
var http = require('http')

//設(shè)置請(qǐng)求監(jiān)聽(tīng)函數(shù)
/**
  *  param req:   請(qǐng)求信息
  *  param res:   響應(yīng)信息
  */
var requestHandler = function (req, res) {
            res.end('hello');
    }

//創(chuàng)建服務(wù)器
var web = http.createServer(requestHandler)

//設(shè)置監(jiān)聽(tīng)端口號(hào)
web.listen(7878)

console.log('http running on http://localhost:7878')

2). $ node web.js


01.png

3).測(cè)試服務(wù)器是否搭建成功
方法一: 新建一個(gè)終端窗口運(yùn)行命令
$ curl http://localhost:7878
方法二: 瀏覽器中打開(kāi)地址
http://localhost:7878

02.png

2. 使用express搭建服務(wù)器

1). 安裝express庫(kù)

$  cd express.js   
$  npm install express

2). 新建文件express.js

//引入express的模塊
var express = require('express');

//創(chuàng)建實(shí)例
var app = express();

//靜態(tài)文件
// http://exapmle.com/static.file
app.use(express.static('./public'));

app.get('/', function (req, res, next) {
  res.end('hello \n')
  next();
})

//設(shè)定監(jiān)聽(tīng)端口, 和回調(diào)函數(shù)
app.listen(7878, function afterListen() {
  console.log('express running on http://localhost:7878');
});

3). 測(cè)試服務(wù)器是否創(chuàng)建成功
方法一: 新建一個(gè)終端窗口運(yùn)行命令

$ curl http://localhost:7878

方法二: 瀏覽器中打開(kāi)地址

http://localhost:7878

3. 搭建TCP服務(wù)器

1). 使用net模塊創(chuàng)建TCP服務(wù)器

2). 使用telnet鏈接TCP服務(wù)器 - 使用telnet進(jìn)行測(cè)試

  1. 安裝telnet
    $ brew install telnet
  2. 測(cè)試鏈接
    $ telnet localhost 18001 //telnet 地址 端口號(hào)
  3. 直接輸入內(nèi)容回車(chē)即可發(fā)送數(shù)據(jù)
    buffer是用來(lái)處理二進(jìn)制和非unicode數(shù)據(jù)的類(lèi), tcp通訊中傳輸?shù)脑紨?shù)據(jù), 在nodejs中便是使用buffer的實(shí)例來(lái)進(jìn)行封裝的
  4. 查看當(dāng)前系統(tǒng)使用的端口號(hào)
    1) netstat 命令 grep篩選結(jié)果
    netstat -an | grep 18001 2) lsof命令 lsof -i :18001
  1. 查看telnet的進(jìn)程 殺死進(jìn)程, 查看鏈接關(guān)閉的效果
//  tcp.js

const PORT = 18001;
const HOST = '127.0.0.1';

//導(dǎo)入核心模塊
var net = require('net');

//監(jiān)聽(tīng)函數(shù)
var clientHandler = function (socket) {
    console.log('someone connected');

    //服務(wù)器端收到客戶端發(fā)送的數(shù)據(jù)
    socket.on('data', function dataHandler(data) {
        console.log(socket.remoteAddress, socket.remotePort, 'send', data.toString())

        //服務(wù)器端向客戶端發(fā)送數(shù)據(jù)
        socket.write('server received \n')
    });

    //鏈接斷開(kāi)
    socket.on('close', function () {
        console.log(socket.remoteAddress, socket.remotePort, 'connect close')
    })

}

//創(chuàng)建服務(wù)器
var app = net.createServer(clientHandler);

app.listen(PORT, HOST);

console.log('TCP server running on tcp://', HOST, ':', PORT);
  1. 使用net創(chuàng)建TCP客戶端
//  tcpClient.js

var net = require('net');

const HOST = '127.0.0.1';

const PORT = 18001;


var tcpClient = net.Socket();

tcpClient.connect(PORT, HOST, function () {
    console.log('connect success');
    tcpClient.write('this is tcp client by Node.js');
});

//接受服務(wù)器端的數(shù)據(jù)
tcpClient.on('data', function (data) {
    console.log('receive: ', data.toString())
})

三. express

1. 使用express創(chuàng)建路由的三種方法

1) . path
//path 方法
app.get('/', function (req, res, next) {
    res.send('express hello')
    res.end(' hello\n')
    next();
})
屏幕快照 2018-06-08 下午2.17.14.png
2). Router
var Router = express.Router();

/**
 * http:/example.com/post/add
 * http:/example.com/post/list
 */

Router.get('/add', function (req, res) {
    res.end('Router add\n' );
})

Router.get('/list', function (req, res) {
    res.end('Router list\n' );
})

app.use('/post', Router)
router.png
3). route
//指定不同方法下的不同的處理, 如post請(qǐng)求和get請(qǐng)求執(zhí)行的操作
//http://example.com/article

app.route('/article')
    .get(function (req, res) {
        res.end('route /article get \n')
    })
    .post(function (req, res) {
        res.end('route /article post\n')
    })

命令行發(fā)起post請(qǐng)求和get請(qǐng)求

//get請(qǐng)求
curl http://localhost:7878 或 curl -X GET http://localhost:7878

//post請(qǐng)求
$ curl -X POST http://localhost:7878

get/post請(qǐng)求.png

2. 指定參數(shù)名
//http://example.com/news/123
app.param('newsId', function(res, req, next, newsId) {
    req.newId = newsId;//將newId賦值給請(qǐng)求參數(shù)
    next();//請(qǐng)求完執(zhí)行的函數(shù)
})

app.get('/news/:newsId', function (req, res) {
    console.log(req.params)
    res.end('newId: ' + req.params.newsId + '\n');
})

3. 中間件

Connect: Node.js 的中間件架構(gòu)
分層處理
每層實(shí)現(xiàn)一個(gè)功能
以打印日志中間件 morgan 為例

1.安裝morgan
$ npm install morgan

   var morgan = require('morgan');  //打印日志

   //中間件
   app.use(morgan());

4. 自動(dòng)生成 express應(yīng)用模板

express生成工具, 直接生成express應(yīng)用模板
全局 安裝 express-generator
npm install -g express-generator express expressHello/
cd expressHello vim package.json 查看執(zhí)行目錄 /bin/www.js
npm install 執(zhí)行模塊安裝, 因?yàn)橐呀?jīng)定義好了, 所以直接執(zhí)行instal node bin/www
$ curl http://localhost:3000 默認(rèn)端口號(hào)實(shí)3000, 鏈接服務(wù)器測(cè)試

5. express的完整代碼

//引入express的模塊
var express = require('express');
var morgan = require('morgan');  //打印日志

//創(chuàng)建實(shí)例
var app = express();

//中間件
app.use(morgan());

//靜態(tài)文件
app.use(express.static('./public'));

//path 方法
app.get('/', function (req, res, next) {
    res.send('express hello \n');
    next();
});

//Router 方法
var Router = express.Router();
/**
 * http:/example.com/post/add
 * http:/example.com/post/list
 */

Router.get('/add', function (req, res) {
    res.end('Router add\n' );
});

Router.get('/list', function (req, res) {
    res.end('Router list\n' );
});

app.use('/post', Router);

//route 方法
//指定不同方法下的不同的處理, 如post請(qǐng)求和get請(qǐng)求執(zhí)行的操作
app.route('/article')
    .get(function (req, res) {
        res.end('route /article get \n')
    })
    .post(function (req, res) {
        res.end('route /article post\n')
    });

//http://example.com/news/123
//指定參數(shù)名
app.param('newsId', function(res, req, next, newsId) {
    req.newsId = newsId;//將newId賦值給請(qǐng)求參數(shù)
    next();//請(qǐng)求完執(zhí)行的函數(shù)
});

app.get('/news/:newsId', function (req, res) {
    console.log(req.params);
    res.end('newsId: ' + req.params.newsId + '\n');
});


//設(shè)定監(jiān)聽(tīng)端口, 和回調(diào)函數(shù)
app.listen(7878, function afterListen() {
    console.log('express running on http://localhost:7878');
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市梅猿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侥祭,死亡現(xiàn)場(chǎng)離奇詭異韩容,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诸老,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钳恕,“玉大人别伏,你說(shuō)我怎么就攤上這事吮廉。” “怎么了畸肆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵宦芦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我轴脐,道長(zhǎng)调卑,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任大咱,我火速辦了婚禮恬涧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碴巾。我一直安慰自己溯捆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布厦瓢。 她就那樣靜靜地躺著提揍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪煮仇。 梳的紋絲不亂的頭發(fā)上劳跃,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音浙垫,去河邊找鬼刨仑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛夹姥,可吹牛的內(nèi)容都是我干的杉武。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辙售,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼轻抱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起圾亏,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤十拣,失蹤者是張志新(化名)和其女友劉穎封拧,沒(méi)想到半個(gè)月后志鹃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泽西,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年曹铃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捧杉。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陕见,死狀恐怖秘血,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情评甜,我是刑警寧澤灰粮,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站忍坷,受9級(jí)特大地震影響粘舟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜佩研,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一柑肴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧旬薯,春花似錦晰骑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至骤公,卻和暖如春岗宣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背淋样。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工耗式, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人趁猴。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓刊咳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親儡司。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娱挨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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