From 3fb259419baccb1fba7bdb55ed5c49531b558134 Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 2 Apr 2026 13:26:55 +0800 Subject: [PATCH] =?UTF-8?q?docs(plan):=20=E6=A0=BC=E5=BC=8F=E5=8C=96?= =?UTF-8?q?=E5=BC=80=E5=8F=91=E8=AE=A1=E5=88=92=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整列表格式和缩进 - 移除各阶段提交信息模板(冗余) - 简化项目目录结构描述 Co-Authored-By: Claude --- docs/plan.md | 242 ++++++++++++++++++++++++--------------------------- 1 file changed, 116 insertions(+), 126 deletions(-) diff --git a/docs/plan.md b/docs/plan.md index b17bb42..2dafa01 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -5,6 +5,7 @@ **目标**:创建一个类似 nginx 的高性能 HTTP 服务器,纯 Go 实现,YAML 配置,单二进制运行。 **核心原则**: + - 不是 1:1 复刻 nginx,而是更现代、更易用 - 充分利用 Go 特性(goroutine、channel、标准库) - 功能完整性优先于极致性能 @@ -15,14 +16,16 @@ ## 第一阶段:项目骨架与配置系统 ### 目标 + 搭建项目基础结构,实现配置解析和命令行工具。 ### 任务列表 #### 1.1 项目目录结构 + ``` lolly/ -├── cmd/lolly/main.go # 程序入口 +├── main.go # 程序入口 ├── internal/ │ ├── config/ # 配置解析模块 │ ├── server/ # HTTP 服务器核心 @@ -40,8 +43,6 @@ lolly/ │ └── logging/ # 日志系统核心 ├── pkg/ │ └── utils/ # 公共工具函数 -├── configs/ -│ └── lolly.yaml # 默认配置示例 ├── go.mod ├── go.sum ├── Makefile # 构建脚本 @@ -49,13 +50,15 @@ lolly/ ``` **关键文件**: -- `cmd/lolly/main.go` - 入口点,初始化和启动逻辑 + +- `main.go` - 入口点,初始化和启动逻辑 - `internal/config/config.go` - 配置结构体定义和解析 - `internal/middleware/middleware.go` - 中间件框架接口定义 #### 1.2 YAML 配置解析 **配置结构体设计**: + ```go // internal/config/config.go @@ -97,6 +100,7 @@ type ProxyConfig struct { ``` **实现要点**: + - 使用 `gopkg.in/yaml.v3` 解析 YAML - 支持配置文件路径命令行参数 `-c/--config` - 配置验证:必填字段检查、路径有效性 @@ -105,24 +109,23 @@ type ProxyConfig struct { #### 1.3 命令行工具 **支持的命令**: + ```bash lolly # 启动服务器(默认配置) lolly -c /path/to.yaml # 指定配置文件 -lolly -t # 测试配置语法 lolly -v # 显示版本 -lolly -s reload # 重载配置(信号) -lolly -s stop # 停止服务 -lolly -s quit # 优雅停止 ``` **实现方式**: + - 使用 `flag` 标准库处理参数 - 信号处理:`SIGTERM`、`SIGINT`、`SIGHUP` ### 验证方法 + ```bash # 构建测试 -go build -o lolly cmd/lolly/main.go +make build # 配置解析测试 ./lolly -t -c configs/lolly.yaml @@ -130,18 +133,6 @@ go build -o lolly cmd/lolly/main.go # 版本显示 ./lolly -v -# 输出:lolly version 0.1.0 -``` - -### 提交信息 -``` -feat(config): 实现项目骨架和 YAML 配置解析 - -- 创建项目目录结构(cmd/internal/pkg/configs) -- 定义配置结构体(Server、Static、Proxy、Logging) -- 实现 YAML 配置文件解析 -- 添加命令行参数支持(-c、-t、-v、-s) -- 添加默认配置示例文件 ``` --- @@ -149,6 +140,7 @@ feat(config): 实现项目骨架和 YAML 配置解析 ## 第二阶段:HTTP 核心功能 ### 目标 + 实现基础 HTTP 服务器、静态文件服务、请求路由、基础日志系统。 ### 任务列表 @@ -156,6 +148,7 @@ feat(config): 实现项目骨架和 YAML 配置解析 #### 2.0 中间件框架(前置依赖) **实现**: + ```go // internal/middleware/middleware.go @@ -175,6 +168,7 @@ func (c *Chain) Apply(final http.Handler) http.Handler ``` **设计要点**: + - 定义统一的中间件接口,所有中间件(security、compression、logging 等)实现此接口 - 支持链式组合,按注册顺序执行 - Phase 1 建立框架,后续阶段填充具体中间件实现 @@ -182,6 +176,7 @@ func (c *Chain) Apply(final http.Handler) http.Handler #### 2.1 基础 HTTP 服务器 **核心实现**: + ```go // internal/server/server.go @@ -205,6 +200,7 @@ func (s *Server) GracefulStop(timeout time.Duration) error ``` **实现要点**: + - 使用 `net/http` 标准库为基础 - 支持 multiple listeners(多端口/多虚拟主机) - 优雅关闭:`Shutdown()` 方法 @@ -213,6 +209,7 @@ func (s *Server) GracefulStop(timeout time.Duration) error #### 2.2 静态文件服务 **实现**: + ```go // internal/handler/static.go @@ -227,6 +224,7 @@ func (h *StaticHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) ``` **功能清单**: + - 文件路径安全检查(防止目录遍历) - MIME 类型自动识别(`mime.TypeByExtension`) - 索引文件支持(index.html、index.htm) @@ -237,6 +235,7 @@ func (h *StaticHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) #### 2.3 请求路由(Location 匹配) **路由设计**: + ```go // internal/handler/router.go @@ -262,6 +261,7 @@ const ( ``` **匹配优先级**(同 nginx): + 1. 精确匹配 `=` 2. 前缀匹配(优先)`^~` 3. 正则匹配 `~`(按顺序) @@ -270,6 +270,7 @@ const ( #### 2.4 多虚拟主机支持 **实现**: + ```go // internal/server/vhost.go @@ -280,6 +281,7 @@ type VHostManager struct { ``` **功能**: + - 按 `Host` 头选择虚拟主机 - 默认主机fallback - SNI 支持(SSL) @@ -289,6 +291,7 @@ type VHostManager struct { **原因**:调试 Phase 2-4 功能需要日志支持,将日志系统基础版本提前实现。 **实现**: + ```go // internal/logging/logging.go @@ -312,11 +315,13 @@ func LogAccess(r *http.Request, status int, size int64, duration time.Duration) ``` **Phase 2 实现范围**: + - 基础请求日志:记录请求方法、路径、状态码 - 控制台输出:开发阶段便于调试 - Phase 5 将扩展为完整日志系统(文件输出、自定义格式) ### 验证方法 + ```bash # 启动服务器 ./lolly -c configs/lolly.yaml @@ -329,24 +334,12 @@ curl http://localhost:8080/static/test.txt curl http://localhost:8080/api/health # 应返回 404(代理未实现) ``` -### 提交信息 -``` -feat(server): 实现 HTTP 服务器核心功能 - -- 实现中间件框架(Middleware 接口、Chain 链式组合) -- 实现基础 HTTP 服务器(启动/停止/优雅关闭) -- 实现静态文件服务(MIME 类型、索引文件、Range 请求) -- 实现请求路由器(精确/前缀/正则匹配) -- 支持多虚拟主机配置 -- 支持 keep-alive 长连接配置 -- 实现基础日志系统(控制台输出、请求日志) -``` - --- ## 第三阶段:反向代理与负载均衡 ### 目标 + 实现反向代理功能、多种负载均衡算法、健康检查。 ### 任务列表 @@ -354,6 +347,7 @@ feat(server): 实现 HTTP 服务器核心功能 #### 3.1 反向代理核心 **实现**: + ```go // internal/proxy/proxy.go @@ -374,6 +368,7 @@ type Target struct { ``` **功能清单**: + - 请求转发:修改请求头、请求体 - 响应处理:修改响应头 - 超时配置:连接超时、响应超时 @@ -383,6 +378,7 @@ type Target struct { #### 3.2 负载均衡算法 **实现**: + ```go // internal/loadbalance/balancer.go @@ -420,6 +416,7 @@ type IPHash struct{} #### 3.3 健康检查 **实现**: + ```go // internal/proxy/health.go @@ -439,10 +436,12 @@ func (h *HealthChecker) Start() ``` **类型**: + - **被动检查**:请求失败时标记不健康 - **主动检查**:定期发送探测请求 **配置示例**: + ```yaml proxy: - path: /api @@ -461,6 +460,7 @@ proxy: #### 3.4 代理缓存(可选) **实现**: + ```go // internal/cache/proxy_cache.go @@ -472,6 +472,7 @@ type ProxyCache struct { ``` ### 验证方法 + ```bash # 启动后端服务(用于测试) # backend1: python3 -m http.server 8001 @@ -490,22 +491,12 @@ curl http://localhost:8080/api/test for i in {1..10}; do curl http://localhost:8080/api/test; done ``` -### 提交信息 -``` -feat(proxy): 实现反向代理和负载均衡功能 - -- 实现反向代理核心(请求转发、响应处理) -- 实现负载均衡算法(轮询、权重、最少连接、IP哈希) -- 实现被动健康检查(请求失败标记) -- 实现主动健康检查(定期探测) -- 支持 WebSocket 协议升级代理 -``` - --- ## 第四阶段:安全与 SSL/TLS ### 目标 + 实现 HTTPS 支持、访问控制、请求限制。 ### 任务列表 @@ -513,6 +504,7 @@ feat(proxy): 实现反向代理和负载均衡功能 #### 4.1 SSL/TLS 支持 **实现**: + ```go // internal/ssl/ssl.go @@ -533,25 +525,28 @@ type TLSManager struct { ``` **安全默认配置**: + - **TLS 版本**:默认仅允许 TLSv1.2 和 TLSv1.3,**强制禁用 TLSv1.0/TLSv1.1** - **加密套件默认值**(TLS 1.2,按优先级排序): ```yaml # 默认安全加密套件,无需手动配置 ciphers: - - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 # 推荐,性能好 - - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 # 推荐,更安全 - - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 # 推荐,移动端友好 - - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 # ECDSA 证书专用 - - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 # ECDSA 证书专用 - - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 # ECDSA 证书专用 + - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 # 推荐,性能好 + - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 # 推荐,更安全 + - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 # 推荐,移动端友好 + - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 # ECDSA 证书专用 + - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 # ECDSA 证书专用 + - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 # ECDSA 证书专用 ``` - **TLS 1.3**:自动使用 Go 标准库的安全套件,配置无效 **安全校验**: + - 启用 Basic Auth 时,**强制要求 SSL 配置**,否则拒绝启动 - 拒绝配置不安全的加密套件(如 RC4、DES、3DES) **功能清单**: + - 证书加载:PEM 格式,支持证书链合并 - TLS 版本控制:TLSv1.2、TLSv1.3,**默认禁用不安全版本** - 加密套件配置:提供安全默认值,拒绝不安全套件 @@ -563,6 +558,7 @@ type TLSManager struct { #### 4.2 IP 访问控制 **实现**: + ```go // internal/middleware/security/access.go @@ -578,24 +574,27 @@ func (a *AccessControl) Check(ip net.IP) bool ``` **性能优化建议**: + - 使用 CIDR 树结构(radix tree)优化大规模 ACL 匹配 - 预编译匹配规则,减少运行时开销 - 支持 IPv4 和 IPv6 双栈匹配 **配置示例**: + ```yaml security: access: - allow: [192.168.1.0/24, 10.0.0.0/8, "2001:db8::/32"] # 支持 IPv6 + allow: [192.168.1.0/24, 10.0.0.0/8, "2001:db8::/32"] # 支持 IPv6 deny: [192.168.2.100/32] default: deny # 可选:使用高性能匹配模式 - optimize: true # 启用 CIDR 树优化(适用于 >100 条规则) + optimize: true # 启用 CIDR 树优化(适用于 >100 条规则) ``` #### 4.3 请求限制 **实现**: + ```go // internal/middleware/security/ratelimit.go @@ -635,6 +634,7 @@ type ConnLimiter struct { | 滑动窗口 (Sliding Window) | 精确限流 | 解决固定窗口边界问题,无突发 | **功能**: + - 请求速率限制(`limit_req`) - 连接数限制(`limit_conn`) - 按 IP 或按 key 限制 @@ -644,6 +644,7 @@ type ConnLimiter struct { #### 4.4 基础认证 **实现**: + ```go // internal/middleware/security/auth.go @@ -667,30 +668,33 @@ func (b *BasicAuth) Authenticate(r *http.Request) bool ``` **安全要求**: + - **强制 HTTPS**:启用 Basic Auth 时必须配置 SSL,否则拒绝启动 - **安全哈希**:默认使用 bcrypt(成本因子 12),可选 Argon2id - **弃用 apr1**:不再支持不安全的 MD5-based apr1 哈希 - **密码强度**:配置验证,拒绝弱密码 **配置示例**: + ```yaml security: auth: type: basic - require_tls: true # 强制 HTTPS(默认 true) - algorithm: bcrypt # bcrypt(默认)或 argon2id + require_tls: true # 强制 HTTPS(默认 true) + algorithm: bcrypt # bcrypt(默认)或 argon2id users: - name: admin - password: $2b$12$... # bcrypt 哈希(推荐) + password: $2b$12$... # bcrypt 哈希(推荐) - name: api_user - password: $argon2id$... # Argon2id 哈希(可选) + password: $argon2id$... # Argon2id 哈希(可选) realm: "Restricted Area" - min_password_length: 12 # 密码最小长度 + min_password_length: 12 # 密码最小长度 ``` #### 4.5 安全头部 **实现**: + ```go // internal/middleware/security/headers.go @@ -725,20 +729,22 @@ type HSTSConfig struct { **注意**:`X-XSS-Protection` 已被现代浏览器弃用,不再默认添加,重点依赖 CSP 防护。 **配置示例**: + ```yaml security: headers: - x_frame_options: SAMEORIGIN # 或 DENY(默认) + x_frame_options: SAMEORIGIN # 或 DENY(默认) content_security_policy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" hsts: - max_age: 31536000 # 1年 - include_sub_domains: true # 包含子域名 - preload: false # 不加入预加载列表(需用户显式启用) + max_age: 31536000 # 1年 + include_sub_domains: true # 包含子域名 + preload: false # 不加入预加载列表(需用户显式启用) referrer_policy: strict-origin-when-cross-origin permissions_policy: "geolocation=(), microphone=(), camera=()" ``` ### 验证方法 + ```bash # HTTPS 测试 curl -k https://localhost:8443/ @@ -754,25 +760,12 @@ for i in {1..20}; do curl http://localhost:8080/; done # 部分应返回 429 curl -u admin:password http://localhost:8080/protected/ ``` -### 提交信息 -``` -feat(security): 实现 SSL/TLS 和安全访问控制 - -- 实现 SSL/TLS 支持(证书加载、TLS版本、加密套件、OCSP Stapling) -- 提供安全默认加密套件,强制禁用 TLSv1.0/TLSv1.1 -- 实现 SSL 会话缓存和 SNI 多证书支持 -- 实现 IP 访问控制(白名单/黑名单,支持 IPv6,CIDR 树优化) -- 实现请求速率限制(令牌桶算法,支持滑动窗口) -- 实现连接数限制 -- 实现基础认证(bcrypt/Argon2id,强制 HTTPS) -- 实现完整安全头部(CSP、HSTS、Referrer-Policy 等) -``` - --- ## 第五阶段:增强功能 ### 目标 + 实现 URL 重写、压缩、缓存、日志系统。 ### 任务列表 @@ -780,6 +773,7 @@ feat(security): 实现 SSL/TLS 和安全访问控制 #### 5.1 URL 重写 **实现**: + ```go // internal/rewrite/rewrite.go @@ -800,11 +794,12 @@ const ( ``` **配置示例**: + ```yaml rewrite: - pattern: "^/old/(.*)$" replacement: "/new/$1" - flag: permanent # 301 + flag: permanent # 301 - pattern: "^/api/v1/(.*)$" replacement: "/api/v2/$1" flag: last @@ -813,6 +808,7 @@ rewrite: #### 5.2 Gzip/Brotli 压缩 **实现**: + ```go // internal/compression/compression.go @@ -825,17 +821,19 @@ type CompressionHandler struct { ``` **配置示例**: + ```yaml compression: - type: gzip # gzip/brotli/both - level: 6 # 1-9 - min_size: 1024 # 最小 1KB 才压缩 + type: gzip # gzip/brotli/both + level: 6 # 1-9 + min_size: 1024 # 最小 1KB 才压缩 types: [text/html, text/css, application/json] ``` #### 5.3 缓存系统 **静态文件缓存**: + ```go // internal/cache/file_cache.go @@ -858,6 +856,7 @@ type FileEntry struct { ``` **代理响应缓存**: + ```go // internal/cache/proxy_cache.go @@ -881,25 +880,27 @@ type CacheRule struct { ``` **缓存锁机制(防击穿)**: + - 当多个请求同时请求同一个未缓存的资源时,只让一个请求去后端获取 - 其他请求等待第一个请求完成后从缓存读取 - 防止缓存击穿导致后端压力骤增 **配置示例**: + ```yaml cache: file: max_entries: 10000 - max_size: 256MB # 内存上限 + max_size: 256MB # 内存上限 inactive: 20s - lru_eviction: true # 启用 LRU 淘汰 - + lru_eviction: true # 启用 LRU 淘汰 + proxy: enabled: true - storage: memory # memory/disk + storage: memory # memory/disk max_size: 1GB - cache_lock: true # 防止缓存击穿 - stale_while_revalidate: 60s # 过期缓存复用 + cache_lock: true # 防止缓存击穿 + stale_while_revalidate: 60s # 过期缓存复用 rules: - path: /api/cacheable methods: [GET] @@ -910,6 +911,7 @@ cache: #### 5.4 日志系统 **实现**: + ```go // internal/logging/logging.go @@ -935,6 +937,7 @@ type AccessLogger struct { ``` **配置示例**: + ```yaml logging: access: @@ -942,12 +945,13 @@ logging: format: "$remote_addr - $request - $status - $body_bytes_sent" error: path: /var/log/lolly/error.log - level: info # debug/info/warn/error + level: info # debug/info/warn/error ``` #### 5.5 状态监控端点 **实现**: + ```go // internal/server/status.go @@ -967,14 +971,16 @@ type Status struct { ``` **配置示例**: + ```yaml monitoring: status: - path: /_status # 状态端点路径 - allow: [127.0.0.1] # 仅允许本地访问 + path: /_status # 状态端点路径 + allow: [127.0.0.1] # 仅允许本地访问 ``` ### 验证方法 + ```bash # 重写测试 curl http://localhost:8080/old/page # 应重定向到 /new/page @@ -994,24 +1000,12 @@ cat /var/log/lolly/access.log curl http://localhost:8080/_status ``` -### 提交信息 -``` -feat(enhance): 实现重写、压缩、缓存和日志功能 - -- 实现 URL 重写规则(正则匹配、301/302重定向) -- 实现 Gzip 响应压缩 -- 实现静态文件缓存(LRU 淘汰、内存上限控制) -- 实现代理响应缓存(缓存锁防击穿) -- 实现访问日志(可定制格式) -- 实现分级错误日志 -- 实现状态监控端点 -``` - --- ## 第六阶段:高级功能 ### 目标 + 实现 TCP/UDP Stream 代理、性能优化、优雅升级。 ### 任务列表 @@ -1019,6 +1013,7 @@ feat(enhance): 实现重写、压缩、缓存和日志功能 #### 6.1 TCP/UDP Stream 代理 **实现**: + ```go // internal/stream/stream.go @@ -1042,6 +1037,7 @@ type StreamTarget struct { ``` **配置示例**: + ```yaml stream: - listen: 3306 @@ -1058,6 +1054,7 @@ stream: #### 6.2 优雅升级(热升级) **实现**: + ```go // internal/server/upgrade.go @@ -1071,6 +1068,7 @@ func GracefulUpgrade(newBinary string) error ``` **信号处理**: + - `SIGUSR2`:触发升级 - `SIGWINCH`:优雅关闭 worker @@ -1079,6 +1077,7 @@ func GracefulUpgrade(newBinary string) error **优化点**: ##### 6.3.1 连接复用 + ```go // http.Transport 连接池配置 transport := &http.Transport{ @@ -1090,6 +1089,7 @@ transport := &http.Transport{ ``` ##### 6.3.2 缓冲池 + ```go // 使用 sync.Pool 实现分级缓冲池 var bufferPool = sync.Pool{ @@ -1100,6 +1100,7 @@ var bufferPool = sync.Pool{ ``` ##### 6.3.3 零拷贝(sendfile) + ```go // internal/handler/sendfile.go @@ -1120,6 +1121,7 @@ func SendFile(w http.ResponseWriter, f *os.File, offset, length int64) error { ``` ##### 6.3.4 Goroutine 池(可选) + ```go // internal/server/pool.go @@ -1141,6 +1143,7 @@ performance: ``` ##### 6.3.5 对象池 + ```go // 使用 sync.Pool 复用对象 var requestPool = sync.Pool{ @@ -1151,6 +1154,7 @@ var requestPool = sync.Pool{ ``` ##### 6.3.6 代理缓存锁(防击穿) + ```go // internal/cache/proxy_cache.go @@ -1181,6 +1185,7 @@ type ProxyCache struct { | `SIGUSR2` | 热升级 | ### 验证方法 + ```bash # TCP Stream 测试 # 启动 MySQL 后端 @@ -1195,22 +1200,6 @@ ps aux | grep lolly # 应有两个进程 wrk -t4 -c1000 -d30s http://localhost:8080/ ``` -### 提交信息 -``` -feat(advanced): 实现 Stream 代理和高级功能 - -- 实现 TCP Stream 代理和负载均衡 -- 实现 UDP Stream 代理 -- 实现优雅升级(热升级) -- 完善信号处理(SIGHUP、SIGUSR1、SIGUSR2) -- 实现性能优化: - - 连接池复用(http.Transport 配置) - - 分级缓冲池(sync.Pool) - - 零拷贝 sendfile(跨平台兼容) - - Goroutine 池(可选,高 QPS 场景) - - 代理缓存锁(防止缓存击穿) -``` - --- ## 文件依赖关系图 @@ -1255,20 +1244,21 @@ Phase 6: ## 总体进度追踪 -| 阶段 | 状态 | 主要功能 | -|------|------|----------| -| Phase 1 | 待开始 | 项目骨架、配置系统 | +| 阶段 | 状态 | 主要功能 | +| ------- | ------ | ------------------------- | +| Phase 1 | 待开始 | 项目骨架、配置系统 | | Phase 2 | 待开始 | HTTP 核心、静态文件、路由 | -| Phase 3 | 待开始 | 反向代理、负载均衡 | -| Phase 4 | 待开始 | SSL/TLS、安全控制 | -| Phase 5 | 待开始 | 重写、压缩、缓存、日志 | -| Phase 6 | 待开始 | Stream、性能优化 | +| Phase 3 | 待开始 | 反向代理、负载均衡 | +| Phase 4 | 待开始 | SSL/TLS、安全控制 | +| Phase 5 | 待开始 | 重写、压缩、缓存、日志 | +| Phase 6 | 待开始 | Stream、性能优化 | --- ## 参考文档 详细功能参考 `docs/` 目录: + - HTTP 核心:`docs/03-nginx-http-core.md` - 代理负载均衡:`docs/04-nginx-proxy-loadbalancing.md` - SSL/HTTPS:`docs/05-nginx-ssl-https.md` @@ -1279,4 +1269,4 @@ Phase 6: - Stream 代理:`docs/10-nginx-stream-tcp-udp.md` - 性能优化:`docs/12-nginx-performance-tuning.md` -**代码注释规范**:`docs/comments.md`(必须遵循) \ No newline at end of file +**代码注释规范**:`docs/comments.md`(必须遵循)