319 lines
13 KiB
Markdown
319 lines
13 KiB
Markdown
|
|
# 开发指南
|
|||
|
|
|
|||
|
|
<cite>
|
|||
|
|
**本文引用的文件**
|
|||
|
|
- [package.json](file://package.json)
|
|||
|
|
- [client/package.json](file://client/package.json)
|
|||
|
|
- [tsconfig.json](file://tsconfig.json)
|
|||
|
|
- [tsconfig.lint.json](file://tsconfig.lint.json)
|
|||
|
|
- [jest.config.js](file://jest.config.js)
|
|||
|
|
- [client/jest.config.js](file://client/jest.config.js)
|
|||
|
|
- [client/jest.setup.js](file://client/jest.setup.js)
|
|||
|
|
- [.eslintrc.cjs](file://.eslintrc.cjs)
|
|||
|
|
- [client/.eslintrc.json](file://client/.eslintrc.json)
|
|||
|
|
- [.editorconfig](file://.editorconfig)
|
|||
|
|
- [run.bat](file://run.bat)
|
|||
|
|
- [.gitignore](file://.gitignore)
|
|||
|
|
- [src/index.ts](file://src/index.ts)
|
|||
|
|
- [src/server.ts](file://src/server.ts)
|
|||
|
|
- [src/class/options.ts](file://src/class/options.ts)
|
|||
|
|
- [src/log.ts](file://src/log.ts)
|
|||
|
|
- [test/httphandler.test.ts](file://test/httphandler.test.ts)
|
|||
|
|
- [test/websockethandler.test.ts](file://test/websockethandler.test.ts)
|
|||
|
|
</cite>
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
1. [简介](#简介)
|
|||
|
|
2. [项目结构](#项目结构)
|
|||
|
|
3. [核心组件](#核心组件)
|
|||
|
|
4. [架构总览](#架构总览)
|
|||
|
|
5. [详细组件分析](#详细组件分析)
|
|||
|
|
6. [依赖关系分析](#依赖关系分析)
|
|||
|
|
7. [性能考虑](#性能考虑)
|
|||
|
|
8. [故障排查指南](#故障排查指南)
|
|||
|
|
9. [结论](#结论)
|
|||
|
|
10. [附录](#附录)
|
|||
|
|
|
|||
|
|
## 简介
|
|||
|
|
本开发指南面向参与“视频流服务器”项目的开发者,目标是帮助你快速搭建本地开发环境、理解代码规范与编码标准、掌握调试与测试技巧、明确扩展开发流程、以及建立版本管理与发布流程的共识。项目采用 Node.js + TypeScript 构建,前端静态资源由服务端托管,支持 WebSocket 与 HTTP 两种信令模式,内置日志系统与 Swagger 文档。
|
|||
|
|
|
|||
|
|
## 项目结构
|
|||
|
|
项目分为服务端与客户端两部分:
|
|||
|
|
- 服务端(src):Express 应用、HTTP 路由、WebSocket 信令、日志与配置等。
|
|||
|
|
- 客户端(client):静态页面与前端脚本,通过 /module 与 /uploads 等路由访问。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
subgraph "服务端(src)"
|
|||
|
|
IDX["入口: index.ts"]
|
|||
|
|
SRV["HTTP服务: server.ts"]
|
|||
|
|
LOG["日志: log.ts"]
|
|||
|
|
OPT["选项: class/options.ts"]
|
|||
|
|
end
|
|||
|
|
subgraph "客户端(client)"
|
|||
|
|
PUB["静态资源: public/*"]
|
|||
|
|
SRC["前端源码: src/*"]
|
|||
|
|
end
|
|||
|
|
IDX --> SRV
|
|||
|
|
SRV --> PUB
|
|||
|
|
SRV --> SRC
|
|||
|
|
SRV --> LOG
|
|||
|
|
IDX --> OPT
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [src/index.ts:1-109](file://src/index.ts#L1-L109)
|
|||
|
|
- [src/server.ts:1-90](file://src/server.ts#L1-L90)
|
|||
|
|
- [src/class/options.ts:1-10](file://src/class/options.ts#L1-L10)
|
|||
|
|
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/index.ts:1-109](file://src/index.ts#L1-L109)
|
|||
|
|
- [src/server.ts:1-90](file://src/server.ts#L1-L90)
|
|||
|
|
|
|||
|
|
## 核心组件
|
|||
|
|
- 入口与启动:命令行参数解析、HTTPS/HTTP 启动、信令类型选择、日志输出。
|
|||
|
|
- HTTP 服务:CORS、JSON/URL 编码中间件、静态资源、Swagger 文档、头像上传接口。
|
|||
|
|
- 日志系统:可配置的日志级别与格式化输出。
|
|||
|
|
- 测试框架:Jest(服务端)、Jest + jsdom(客户端),覆盖 HTTP 与 WebSocket 信令逻辑。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/index.ts:1-109](file://src/index.ts#L1-L109)
|
|||
|
|
- [src/server.ts:1-90](file://src/server.ts#L1-L90)
|
|||
|
|
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
|
|||
|
|
- [jest.config.js:1-196](file://jest.config.js#L1-L196)
|
|||
|
|
- [client/jest.config.js:1-196](file://client/jest.config.js#L1-L196)
|
|||
|
|
|
|||
|
|
## 架构总览
|
|||
|
|
下图展示从浏览器到服务端的典型请求链路,包括静态资源、信令与上传接口。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant Browser as "浏览器"
|
|||
|
|
participant Express as "Express 应用(server.ts)"
|
|||
|
|
participant Signaling as "信令(HTTP/WebSocket)"
|
|||
|
|
participant FS as "文件系统(头像上传)"
|
|||
|
|
Browser->>Express : GET /
|
|||
|
|
Express-->>Browser : 返回首页(静态资源)
|
|||
|
|
Browser->>Express : GET /config
|
|||
|
|
Express-->>Browser : 返回运行配置
|
|||
|
|
Browser->>Express : GET /signaling/*
|
|||
|
|
Express->>Signaling : 转发至 HTTP 信令处理器
|
|||
|
|
Browser->>Express : POST /api/upload/avatar
|
|||
|
|
Express->>FS : 写入头像并重命名
|
|||
|
|
FS-->>Express : 返回结果
|
|||
|
|
Express-->>Browser : JSON 响应
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [src/server.ts:25-87](file://src/server.ts#L25-L87)
|
|||
|
|
- [src/index.ts:75-90](file://src/index.ts#L75-L90)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/server.ts:1-90](file://src/server.ts#L1-L90)
|
|||
|
|
- [src/index.ts:1-109](file://src/index.ts#L1-L109)
|
|||
|
|
|
|||
|
|
## 详细组件分析
|
|||
|
|
|
|||
|
|
### 启动与配置(index.ts)
|
|||
|
|
- 支持命令行参数:端口、HTTPS 证书、信令类型、通信模式、日志级别。
|
|||
|
|
- 自动检测本机 IPv4 地址并输出访问地址。
|
|||
|
|
- 根据信令类型启动 HTTP 轮询或 WebSocket 信令服务。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
Start(["进程启动"]) --> ParseArgs["解析命令行参数"]
|
|||
|
|
ParseArgs --> CreateApp["创建 Express 应用"]
|
|||
|
|
CreateApp --> Mode{"是否启用 HTTPS?"}
|
|||
|
|
Mode --> |是| HTTPS["读取密钥与证书并监听"]
|
|||
|
|
Mode --> |否| HTTP["以 HTTP 监听"]
|
|||
|
|
HTTPS --> DetectIP["检测本机 IPv4 地址"]
|
|||
|
|
HTTP --> DetectIP
|
|||
|
|
DetectIP --> SigType{"信令类型"}
|
|||
|
|
SigType --> |websocket| WS["初始化 WebSocket 信令"]
|
|||
|
|
SigType --> |http| HTTPSig["初始化 HTTP 轮询信令"]
|
|||
|
|
WS --> Done(["完成"])
|
|||
|
|
HTTPSig --> Done
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [src/index.ts:14-105](file://src/index.ts#L14-L105)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/index.ts:1-109](file://src/index.ts#L1-L109)
|
|||
|
|
- [src/class/options.ts:1-10](file://src/class/options.ts#L1-L10)
|
|||
|
|
|
|||
|
|
### HTTP 服务与静态资源(server.ts)
|
|||
|
|
- 中间件:CORS、JSON、URL 编码、日志(Morgan)。
|
|||
|
|
- 路由:
|
|||
|
|
- GET /config:返回运行配置(信令类型、模式、日志级别)。
|
|||
|
|
- /signaling:转发至信令模块。
|
|||
|
|
- 静态资源:/ 与 /module。
|
|||
|
|
- 上传接口:POST /api/upload/avatar,使用 Multer 存储并按用户 ID 重命名。
|
|||
|
|
- /uploads:公开头像目录。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
Req["请求进入"] --> CORS["CORS 允许所有来源"]
|
|||
|
|
CORS --> Body["解析 JSON/URL 编码"]
|
|||
|
|
Body --> Log{"日志级别允许?"}
|
|||
|
|
Log --> |是| Morgan["Morgan 访问日志"]
|
|||
|
|
Log --> |否| Skip["跳过日志"]
|
|||
|
|
Morgan --> Routes["分发路由"]
|
|||
|
|
Skip --> Routes
|
|||
|
|
Routes --> Config["GET /config"]
|
|||
|
|
Routes --> Signaling["GET/POST /signaling/*"]
|
|||
|
|
Routes --> Static["静态资源: / 与 /module"]
|
|||
|
|
Routes --> Upload["POST /api/upload/avatar"]
|
|||
|
|
Routes --> PublicUploads["GET /uploads/*"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [src/server.ts:14-89](file://src/server.ts#L14-L89)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/server.ts:1-90](file://src/server.ts#L1-L90)
|
|||
|
|
|
|||
|
|
### 日志系统(log.ts)
|
|||
|
|
- 提供多级日志:none/error/warn/log/info。
|
|||
|
|
- 可通过字符串解析日志级别。
|
|||
|
|
- 输出包含时间戳与级别前缀。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/log.ts:1-51](file://src/log.ts#L1-L51)
|
|||
|
|
|
|||
|
|
### 测试与断言(Jest)
|
|||
|
|
- 服务端测试:覆盖 HTTP 信令在 public/private 模式下的行为,含超时清理逻辑。
|
|||
|
|
- 客户端测试:Jest + jsdom 环境,通过 setup 注入 fetch、TextEncoder/Decoder、RTCPeerConnection 等缺失对象。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [test/httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510)
|
|||
|
|
- [test/websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191)
|
|||
|
|
- [client/jest.setup.js:1-35](file://client/jest.setup.js#L1-L35)
|
|||
|
|
|
|||
|
|
## 依赖关系分析
|
|||
|
|
- 语言与构建:TypeScript、ts-node、Jest、ESLint。
|
|||
|
|
- Web 框架:Express、ws(WebSocket)、Multer(文件上传)。
|
|||
|
|
- 文档:Swagger JSdoc、Swagger UI Express。
|
|||
|
|
- 日志:Morgan。
|
|||
|
|
- 工具:Commander(命令行解析)。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
Pkg["package.json 依赖"] --> TS["TypeScript 运行时"]
|
|||
|
|
Pkg --> Express["Express"]
|
|||
|
|
Pkg --> WS["ws"]
|
|||
|
|
Pkg --> Mul["Multer"]
|
|||
|
|
Pkg --> Swagger["Swagger UI Express"]
|
|||
|
|
Pkg --> Morgan["Morgan"]
|
|||
|
|
Pkg --> Cmdr["Commander"]
|
|||
|
|
Pkg --> Jest["Jest"]
|
|||
|
|
Pkg --> ESL["ESLint + TS 插件"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
图表来源
|
|||
|
|
- [package.json:14-46](file://package.json#L14-L46)
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [package.json:1-60](file://package.json#L1-L60)
|
|||
|
|
|
|||
|
|
## 性能考虑
|
|||
|
|
- 上传路径:头像上传使用磁盘存储,建议在生产环境挂载独立持久卷并限制文件大小与类型。
|
|||
|
|
- 日志级别:默认 info,可在高并发场景调低日志级别以减少 I/O。
|
|||
|
|
- 静态资源:Express 静态托管适合开发,生产建议使用 CDN 或反向代理缓存。
|
|||
|
|
- 信令:WebSocket 在高并发下优于 HTTP 轮询,建议优先使用 websocket 模式。
|
|||
|
|
|
|||
|
|
## 故障排查指南
|
|||
|
|
- 启动失败(HTTPS 证书):确认 server.key 与 server.cert 存在且可读;或禁用 HTTPS 并使用 HTTP。
|
|||
|
|
- 无法访问 /uploads:确保 uploads 目录存在且可读写。
|
|||
|
|
- 上传失败:检查 Multer 配置与权限,查看服务端错误日志。
|
|||
|
|
- 测试失败(jsdom 缺失 API):确保使用客户端 jest.config 的 setup 文件已加载。
|
|||
|
|
- 超时会话未清理:检查 HTTP 信令测试中的超时轮询逻辑与清理触发点。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/server.ts:44-87](file://src/server.ts#L44-L87)
|
|||
|
|
- [client/jest.setup.js:1-35](file://client/jest.setup.js#L1-L35)
|
|||
|
|
- [test/httphandler.test.ts:194-309](file://test/httphandler.test.ts#L194-L309)
|
|||
|
|
|
|||
|
|
## 结论
|
|||
|
|
本项目提供了清晰的服务端架构与完善的测试体系,支持 WebSocket 与 HTTP 两种信令模式,并内置日志与文档能力。遵循本文的开发与测试规范,可高效地进行功能扩展与维护。
|
|||
|
|
|
|||
|
|
## 附录
|
|||
|
|
|
|||
|
|
### 开发环境搭建步骤
|
|||
|
|
- 安装 Node.js 与 npm(建议使用版本管理器以避免版本冲突)。
|
|||
|
|
- 克隆仓库后,在根目录与 client 目录分别执行安装依赖命令。
|
|||
|
|
- 准备 HTTPS 证书(可选):若启用 HTTPS,需准备 server.key 与 server.cert。
|
|||
|
|
- 使用提供的脚本启动开发服务或打包产物。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [package.json:5-12](file://package.json#L5-L12)
|
|||
|
|
- [client/package.json:5-8](file://client/package.json#L5-L8)
|
|||
|
|
- [run.bat:1-17](file://run.bat#L1-L17)
|
|||
|
|
|
|||
|
|
### 代码规范与编码标准
|
|||
|
|
- 统一缩进与换行:EditorConfig 规定空格缩进、LF 换行、UTF-8 字符集。
|
|||
|
|
- TypeScript 规范:ESLint 配置启用 @typescript-eslint 推荐规则,强制分号。
|
|||
|
|
- JavaScript 规范(客户端):ESLint 配置启用 jest 插件与推荐规则,强制分号。
|
|||
|
|
- 代码风格:遵循 EditorConfig 与 ESLint 规则,保持一致的排版与语法。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [.editorconfig:10-20](file://.editorconfig#L10-L20)
|
|||
|
|
- [.eslintrc.cjs:1-25](file://.eslintrc.cjs#L1-L25)
|
|||
|
|
- [client/.eslintrc.json:1-23](file://client/.eslintrc.json#L1-L23)
|
|||
|
|
|
|||
|
|
### 调试技巧与开发工具
|
|||
|
|
- 本地启动:使用开发脚本启动服务,自动监听 TypeScript 源码变化。
|
|||
|
|
- 单元测试:使用 Jest 运行服务端与客户端测试,关注覆盖率与断言。
|
|||
|
|
- 信令调试:根据运行日志确认信令类型与模式,必要时降低日志级别以便观察。
|
|||
|
|
- 上传调试:通过 /uploads 访问上传后的头像,验证重命名与路径。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [package.json:5-12](file://package.json#L5-L12)
|
|||
|
|
- [jest.config.js:1-196](file://jest.config.js#L1-L196)
|
|||
|
|
- [client/jest.config.js:1-196](file://client/jest.config.js#L1-L196)
|
|||
|
|
- [src/server.ts:62-87](file://src/server.ts#L62-L87)
|
|||
|
|
|
|||
|
|
### 扩展开发机制
|
|||
|
|
- 新增 HTTP 路由:在 server.ts 中添加路由与处理逻辑,注意中间件顺序与错误处理。
|
|||
|
|
- 新增 WebSocket 事件:在 WebSocket 信令模块中新增事件处理函数,并在测试中补充断言。
|
|||
|
|
- 新增测试用例:在 test 目录下新增对应测试文件,复用现有的公共断言与模拟数据。
|
|||
|
|
- 修改现有功能:遵循最小变更原则,先写测试,再实现修复或增强。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/server.ts:14-89](file://src/server.ts#L14-L89)
|
|||
|
|
- [test/httphandler.test.ts:1-510](file://test/httphandler.test.ts#L1-L510)
|
|||
|
|
- [test/websockethandler.test.ts:1-191](file://test/websockethandler.test.ts#L1-L191)
|
|||
|
|
|
|||
|
|
### 版本管理、分支策略与发布流程
|
|||
|
|
- 版本号:项目使用语义化版本(package.json 中 version 字段)。
|
|||
|
|
- 分支策略:建议采用 Git Flow,主分支用于稳定版本,开发分支用于迭代。
|
|||
|
|
- 发布流程:本地构建(build)、测试(test)、打包(pack),生成可执行包或容器镜像后发布。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [package.json:2-4](file://package.json#L2-L4)
|
|||
|
|
- [package.json:5-12](file://package.json#L5-L12)
|
|||
|
|
|
|||
|
|
### 贡献指南与代码审查标准
|
|||
|
|
- 提交前:运行 lint 与 test,确保通过。
|
|||
|
|
- 提交流程:提交变更到功能分支,发起 Pull Request,至少一名维护者审查。
|
|||
|
|
- 代码审查要点:功能正确性、边界条件、错误处理、日志与安全、测试覆盖、性能影响。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [package.json:11-12](file://package.json#L11-L12)
|
|||
|
|
- [jest.config.js:1-196](file://jest.config.js#L1-L196)
|
|||
|
|
- [client/jest.config.js:1-196](file://client/jest.config.js#L1-L196)
|
|||
|
|
|
|||
|
|
### 常见问题与最佳实践
|
|||
|
|
- 问题:浏览器跨域访问受限
|
|||
|
|
- 解决:服务端已启用 CORS,确保请求头与路径正确。
|
|||
|
|
- 问题:WebSocket 连接失败
|
|||
|
|
- 解决:确认信令类型为 websocket,检查服务端日志与防火墙设置。
|
|||
|
|
- 问题:头像上传失败
|
|||
|
|
- 解决:确认上传目录存在且可写,检查文件类型与大小限制。
|
|||
|
|
- 最佳实践:在生产环境使用 HTTPS、CDN 加速静态资源、合理设置日志级别与轮询间隔。
|
|||
|
|
|
|||
|
|
章节来源
|
|||
|
|
- [src/server.ts:22-24](file://src/server.ts#L22-L24)
|
|||
|
|
- [src/server.ts:44-87](file://src/server.ts#L44-L87)
|
|||
|
|
- [src/index.ts:55-74](file://src/index.ts#L55-L74)
|