NodeJs 中的 http、https 和 http2

本人博客文章地址:點擊進入

一、 HTTP

1. http.server

  • 創建服務器
import http from 'http';

const server = http.createServer((req, res) => {
    res.end();
}).listen(8780);
  • 設置超時時間(默認是120s)
server.setTimeout(60 * 1000, () => {
    console.log('超時回調');
});
  • 服務器錯誤處理(實現端口被占用時自動更換端口)
import http from 'http';

let port = 80;
const createServer = () => {

    const server = http.createServer((req, res) => {
        res.end("hello");
    }).listen(port);

    console.log("Server running on port:" + port);

    server.on('error', (e) => {
        if (e.code === 'EADDRINUSE') {
            console.log(`端口:${e.port} 被占用`);
            port++;
            createServer();
        }
    });
};
createServer();
  • 關閉服務器
server.close(); // 服務器停止接受新的連接
server.on('close', () => {
    // 服務器最后一個連接關閉時調用
});

2. http.IncomingMessage

  • 獲取請求頭
import http from 'http';

const server = http.createServer((req, res) => {
    console.log(req.headers);// 返回的是header中屬性組成的對象
    res.end();
}).listen(8080);
  • 獲取請求方法
import http from 'http';

const server = http.createServer((req, res) => {
    if (req.method == 'GET') {}
    if (req.method == 'POST') {}
    res.end();
}).listen(8080);
  • 獲取請求url與GET、POST參數
import http from 'http';
import URL from 'url';
import querystring from 'querystring';

const server = http.createServer((req, res) => {
    const url = URL.parse(req.url, true);
    console.log(url); // 獲取URL
    if (req.method == "GET") {
        console.log(url.query);// 獲取GET參數
    }
    if (req.method == "POST") {
        let body = "";
        req.on('data', function (chunk) {
            body += chunk;
        });
        req.on('end', function () {
            const postQuery = querystring.parse(decodeURI(body));// 獲取POST參數
        });
    }
    res.end();
}).listen(8080);

3. http.ServerResponse

  • 寫入響應頭
import http from 'http';

const server = http.createServer((req, res) => {
    res.setHeader('Content-Type', 'text/html');
    res.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
    res.end();
}).listen(8780);
  • 寫入響應體
import http from 'http';

const server = http.createServer((req, res) => {
    res.write('{name:"liuhuihao"}');
    res.end();
}).listen(8780);

二、 HTTPS

image.png

1. 創建公鑰、私鑰及證書

  • 創建私鑰
openssl genrsa -out privatekey.pem 1024
  • 創建證書簽名請求
openssl req -new -key privatekey.pem -out certrequest.csr
  • 獲取證書,線上證書需要經過證書授證中心簽名的文件;下面只創建一個學習使用證書
openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
  • 創建pfx文件
openssl pkcs12 -export -in certificate.pem -inkey privatekey.pem -out certificate.pfx

2. http.server

  • 創建服務器
import https from 'https';
import fs from 'fs';

const options = {
    key: fs.readFileSync('dist/privatekey.pem'), // 私鑰
    cert: fs.readFileSync('dist/certificate.pem') // 公鑰
};

https.createServer(options, (req, res) => {
    res.end();
}).listen(8000);

三、 HTTP2

1. 優勢

(1)多路復用 - 雪碧圖、多域名CDN、接口合并

這是一個HTTP2的演示地址,分別用HTTP/1.1和HTTP/2請求379張圖片,對比出HTTP/2在速度上的優勢

image.png

打開控制臺查看網絡請求,我們可以發現HTTP/2和HTTP/1.1的明顯區別

HTTP/1.1:


image.png

HTTP/2:


image.png

由上圖可以看出,多路復用允許同時通過單一的 HTTP/2 連接發起多重的請求-響應消息;而HTTP/1.1協議中,瀏覽器客戶端在同一時間,針對同一域名下的請求有一定數量限制。超過限制數目的請求會被阻塞

image.png

首部壓縮

  • http/1.x 的 header 由于 cookie 和 user agent很容易膨脹,而且每次都要重復發送。http/2使用 encoder 來減少需要傳輸的 header 大小,通訊雙方各自 cache一份 header fields 表,既避免了重復 header 的傳輸,又減小了需要傳輸的大小。高效的壓縮算法可以很大的壓縮 header,減少發送包的數量從而降低延遲

服務端推送

  • 服務端推送是一種在客戶端請求之前發送數據的機制。在 HTTP/2 中,服務器可以對客戶端的一個請求發送多個響應。舉個例子,如果一個請求請求的是index.html,服務器很可能會同時響應index.html、logo.jpg 以及 css 和 js 文件,因為它知道客戶端會用到這些東西。這相當于在一個 HTML 文檔內集合了所有的資源。
image.png

2. nodeJS http/2 實踐

  • 搭建http/2 服務器
import http2 from 'http2';
import fs from 'fs';

const options = {
    key: fs.readFileSync('dist/privatekey.pem'), // 私鑰
    cert: fs.readFileSync('dist/certificate.pem') // 公鑰
};

http2.createSecureServer(options, (req, res) => {
    res.end();
}).listen(8078);

  • 驗證 http/2 多路復用
import http2 from 'http2';
import fs from 'fs';
import URL from 'url';
import mime from 'mime';

const {HTTP2_HEADER_PATH} = http2.constants;// :path

const options = {
    key: fs.readFileSync('dist/privatekey.pem'), // 私鑰
    cert: fs.readFileSync('dist/certificate.pem') // 公鑰
};

http2.createSecureServer(options, (req, res) => {
    const url = URL.parse(req.url, true);
    if (url.pathname != "/" && url.pathname != "/favicon.ico") {
        const indexObj = getFdAndHeader(url.pathname);
        res.stream.respondWithFD(indexObj.fd, indexObj.headers);
    } else {
        const indexObj = getFdAndHeader('more.html');
        res.stream.respondWithFD(indexObj.fd, indexObj.headers);
    }
}).listen(8078);

const getFdAndHeader = (fileName) => {
    const filePath = "public/" + fileName;
    const fd = fs.openSync(filePath, 'r');
    const stat = fs.fstatSync(fd);
    const headers = {
        'content-length': stat.size,
        'last-modified': stat.mtime.toUTCString(),
        'content-type': mime.lookup(filePath)
    };
    return {fd, headers};
};

效果:


image.png
  • 實現 http/2 服務端推送
import http2 from 'http2';
import fs from 'fs';
import mime from 'mime';

const {HTTP2_HEADER_PATH} = http2.constants;// :path

const options = {
    key: fs.readFileSync('dist/privatekey.pem'), // 私鑰
    cert: fs.readFileSync('dist/certificate.pem') // 公鑰
};

http2.createSecureServer(options, (req, res) => {
    const indexObj = getFdAndHeader('index.html');
    const jsObj = getFdAndHeader('someJs.js');
    const cssObj = getFdAndHeader('someCss.css');

    push(res.stream, jsObj);
    push(res.stream, cssObj);

    res.stream.respondWithFD(indexObj.fd, indexObj.headers);

}).listen(8078);

function push(stream, obj) {
    stream.pushStream({[HTTP2_HEADER_PATH]: obj.urlPath}, (pushStream) => {
        pushStream.respondWithFD(obj.fd, obj.headers)
    })
}

const getFdAndHeader = (fileName) => {
    const filePath = "public/" + fileName;
    const fd = fs.openSync(filePath, 'r');
    const stat = fs.fstatSync(fd);
    const urlPath = "/" + fileName;
    const headers = {
        'content-length': stat.size,
        'last-modified': stat.mtime.toUTCString(),
        'content-type': mime.lookup(filePath)
    };
    return {fd, headers, urlPath};
};

推送效果:


image.png

無推送效果:


image.png

作者博客地址:https://liuhuihao.com
作者gitHub:https://github.com/geminate

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容

  • 最近熱播的電視劇《人民的名義》一直傲居熱搜榜首位,剛開始并沒有多想看的欲望,這名字似乎勾不起我半點興趣。但當我看完...
    半象花閱讀 486評論 20 0
  • 中產階級是世界范圍內都在廣泛討論的群體,在中國,根據經濟收入,大約1億人口可以被歸入中產階級的行列,比例固然很低,...
    塵世知行者閱讀 197評論 0 0
  • 我們就那樣靜靜地走著,突然,感覺胳膊上有點濕濕涼涼的東西。我仔細一看,是雨滴! “啊,下雨啦!”我大叫起來。 李劍...
    小喬xiaoqiao閱讀 438評論 3 3