Nest服务端开发与原理深度刨析

有使用过 Nodejs 开发过服务端吗?

服务端开发基础

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,适合用于构建服务端应用程序。由于它的单线程、事件驱动和异步 I/O 模型,Node.js 尤其适合高并发的应用场景,例如 Web 服务器、实时应用和网络通信。

Node.js HTTP服务端开发

创建基本的HTTP服务器

Node.js的核心模块 http 提供了 HTTP 服务器的基本功能。通过这个模块,我们可以快速创建一个服务来处理 HTTP 请求和响应。

const http = require('http');
// 创建 HTTP 服务器
const server = http.createServer((req.res) => {
// 设置响应头
res.writeHead(200, {'Content-Type': 'text/plain'});
// 返回响应内容
res.end('Hello, MaxKin!/n');
});
// 监听端口
server.listen(3000, () => {
console.log('Server running at http://127.0.0.1:3000/');
});

在这个示例中,我们创建了一个简单的 HTTP 服务器,它监听端口 3000,并在每次请求时返回“Hello, MaxKin!”的响应。 http.createServer()方法接受一个回调函数,这个回调函数会在每次收到 HTTP 请求时执行。

处理URL和参数请求

通过解析 URL 和请求参数,我们可以根据请求路径或查询字符串来处理不同的业务逻辑。

const url = require('url');

const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true); // 解析 URL

// 处理不同的请求路径
if (parsedUrl.pathname === '/') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Home Page</h1>');
} else if (parsedUrl.pathname === '/about') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>About Page</h1>');
} else {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('<h1>404 Not Found</h1>');
}
});

server.listen(3000, () => {
console.log('Server running at http://127.0.0.1:3000/');
});

处理POST请求

对于 POST 请求,Node.js 也可以处理请求体数据,通常需要监听 dataend 事件来处理数据流。

const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';

// 监听数据传入
req.on('data', chunk => {
body += chunk.toString(); // 将二进制数据转为字符串
});

// 数据接收完成
req.on('end', () => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Data received', data: body }));
});
}
});

server.listen(3000, () => {
console.log('Server running at http://127.0.0.1:3000/');
});

WebSocket实现实时通信

WebSocket 是一种基于 TCP 的协议,它实现了全双工通信,使得客户端和服务器可以在建立初次连接后,进行持续的、实时的双向数据通信。相较于传统的 HTTP 请求响应模型,WebSocket 极大提升了数据交互的效率,尤其适用于需要频繁通信的场景,例如实时聊天、股票行情、游戏等。

WebSocket通信的实现过程

下面的代码通过 Node.js 原生模块实现了 WebSocket 的基础原理,包括 HTTP 升级、数据帧处理等。整个过程分为四个步骤:

  1. 通过 HTTP 创建一个服务:首先我们需要启动一个 HTTP 服务器,等待客户端发起连接请求。
  2. 升级协议:当客户端请求 WebSocket 连接时,服务器通过 HTTP 101 状态码切换协议,升级为 WebSocket。
  3. 建立 WebSocket 连接:一旦协议升级成功,服务器和客户端就可以通过 WebSocket 进行通信。
  4. WebSocket 通信:双方通过特定格式的数据帧进行消息的发送与接收。
代码实现
import http from "node:http";
import crypto from "node:crypto";

// 1. 创建一个 http server
const server = http.createServer((req, res) => {
console.log("http server", http.STATUS_CODES);
const errorCode = 400;
res.writeHead(errorCode, {
"Content-Type": "text/plain",
});
res.end(
`${http.STATUS_CODES[errorCode]}` // 你不能这样访问,因为我是一个 ws 服务
);
});

// 2. 升级协议
server.on("upgrade", (req, socket, head) => {
const key = req.headers['sec-websocket-key'];
const acceptValue = generateAcceptValue(key);
const resHeaders = [
"HTTP/1.1 101 Switching Protocols",
"Upgrade: websocket",
"Connection: Upgrade",
`Sec-WebSocket-Accept: ${acceptValue}`,
];

// 发送 WebSocket 协议切换的响应头
socket.write(resHeaders.join("\r\n") + "\r\n\r\n");

/**
* 数据接收
*/
socket.on("data", (buffer) => {
// 接收到的数据是 websocket 帧,直接 toString 可能会有问题
console.log("收到的数据帧:", buffer.toString());

// 发送一个 pong 响应
socket.write(generateWebSocketFrame("pong"));
});

/**
* 发送消息
*/
const frame = generateWebSocketFrame("hello");
socket.write(frame);
});

// 监听 3000 端口
server.listen(3000, () => {
console.log("server is running on http://localhost:3000");
});

/**
* 根据客户端的 websocket key 生成 Sec-WebSocket-Accept 值
*/
function generateAcceptValue(secureWebSocketKey: string) {
return crypto
.createHash("sha1")
.update(secureWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", "binary")
.digest("base64");
}

/**
* 生成 WebSocket 数据帧
* @param data 要发送的文本消息
*/
function generateWebSocketFrame(data: string) {
// 将字符串转换为 buffer 处理
const message = Buffer.from(data);

// 分配一个新的 buffer 存储 websocket 帧
const frame = Buffer.alloc(2 + message.length);

// 数据帧的第一个字节是标志位,表示 FIN 位和操作码 (0x01 代表 FIN = 1 和 Text Frame)
frame[0] = 0x01;

// 数据帧的第二个字节表示数据长度(小于 126 的情况)
frame[1] = message.length;

// 将消息内容拷贝到 frame 中,从第三个字节开始
message.copy(frame, 2);

console.log("生成的数据帧:", message, frame);

return frame;
}
代码详解
  1. 创建 HTTP 服务:首先我们创建了一个普通的 HTTP 服务器,当客户端通过 HTTP 请求时,返回 400 错误码,表明该服务仅支持 WebSocket 连接。
  2. 升级协议:当客户端发送Upgrade: websocket请求头时,服务器会捕获到upgrade事件。在这个事件处理程序中,我们通过Sec-WebSocket-Accept头部完成 WebSocket 协议的升级。
    • Sec-WebSocket-Accept是通过客户端发来的Sec-WebSocket-Key计算出的一个 Base64 编码的字符串,确保通信的合法性。
    • 完成协议升级后,服务器可以通过双工连接 (socket) 与客户端通信。
  3. WebSocket 数据帧:WebSocket 的通信是基于数据帧的。在这个例子中, generateWebsocketFrame函数构造了一个简单的文本帧,消息内容为 “hello”。WebSocket 帧由标志位、数据长度和实际数据组成。
  4. 通信过程:一旦 WebSocket 连接建立,服务器可以接收客户端发送的数据,并可以使用socket.write发送数据帧给客户端,实现双向通信。

使用 Express 简化 HTTP 开发

Express 概述

Express是一个基于 Node.js 的 Web 框架,提供了简洁的 API 和丰富的中间件支持,能够帮助开发者快速构建 Web 应用。

使用 Express 创建基本 HTTP 服务器

Express 可以极大地简化 HTTP 服务器的创建和路由管理。

const express = require('express');
const app = express();

// 设置基本路由
app.get('/', (req, res) => {
res.send('Hello, Express!');
});

app.get('/about', (req, res) => {
res.send('About Page');
});

// 启动服务器
app.listen(3000, () => {
console.log('Express server running at http://127.0.0.1:3000/');
});

与原生http模块相比,Express 提供了更强大的路由系统和中间件机制,使开发者能够更高效地处理请求。

中间件机制

Express 中的中间件是处理请求和响应的核心机制。我们可以通过中间件来处理请求数据、验证权限、日志记录等操作。

const express = require('express');
const app = express();

// 中间件示例
app.use((req, res, next) => {
console.log(`Request received: ${req.method} ${req.url}`);
next(); // 调用 next() 继续执行
});

// 路由
app.get('/', (req, res) => {
res.send('Hello, Express with Middleware!');
});

// 启动服务器
app.listen(3000, () => {
console.log('Express server with middleware running at http://127.0.0.1:3000/');
});

你认为设计一个好的服务端架构体系,需要包含哪些模块和结构?

设计一个好的服务端架构体系,涉及到多个核心模块和结构,确保服务的性能、可维护性、安全性以及扩展性。以及常用的设计模式、架构原则(如 MVC)、数据库驱动等其他重要部分。
架构图

网络层

  • HTTP服务器:这是服务端最基础的部分,通过 HTTP 协议处理请求与响应。通过路由解析 URL,分发给相应的控制器来处理不同的请求类型。可以使用Node.jshttp 模块或使用更高层的框架如Express.
  • WebSocket:用于实时通信,支持双向通信,通常用于需要实时更新的场景,如在线聊天、游戏等。Node.js 提供第三方库如ws 来实现 WebSocket。
  • TCP/IP通信:Node.js 的net模块可以用于实现底层 TCP 连接,适用于需要持久连接和高性能传输的场景,比如文件传输或实时流媒体。

鸽了,还没更新完,敬请期待