本人博客文章地址:點擊進入
一、 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