admin 发布的文章

Git 使用 SSH 连接 GitHub 完整教程

一、SSH 方式简介
SSH 是 GitHub 推荐的安全连接方式,相比 HTTPS:

  • 不需要每次输入账号密码

  • 更稳定,不容易出现 connection reset

  • 适合长期开发使用


二、检查是否已有 SSH Key

在 CMD 或 Git Bash 执行:

dir %USERPROFILE%.ssh

如果看到以下文件之一,说明已有 SSH Key:

  • id_ed25519

  • id_ed25519.pub

  • id_rsa

  • id_rsa.pub


三、生成 SSH Key(没有才需要)

执行:

ssh-keygen -t ed25519 -C "你的GitHub邮箱"

一路回车即可(不要设置密码也可以)

默认生成位置:
C:\Users\你的用户名.ssh\


四、启动 SSH Agent

执行:

ssh-agent

如果 Windows 环境需要手动启动服务(管理员 PowerShell):

Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent


五、添加 SSH Key 到代理

执行(以 ed25519 为例):

ssh-add %USERPROFILE%.ssh\id_ed25519

成功会提示:
Identity added


六、复制公钥

执行:

type %USERPROFILE%.ssh\id_ed25519.pub

复制输出的整段内容(ssh-ed25519 开头)


七、添加到 GitHub

打开 GitHub SSH Key 页面:
https://github.com/settings/keys

点击:New SSH key

填写:
Title:随便写(如 My PC)
Key:粘贴公钥内容

点击保存


八、测试 SSH 是否成功

执行:

ssh -T git@github.com

第一次会提示:
Are you sure you want to continue connecting? (yes/no)
输入:yes

成功后显示:
Hi 用户名! You've successfully authenticated


九、修改 Git 远程仓库为 SSH

进入项目目录:

cd 项目路径

执行:

git remote set-url origin git@github.com:用户名/仓库名.git


十、确认远程地址

git remote -v

正确结果示例:
origin git@github.com:username/repo.git (fetch)
origin git@github.com:username/repo.git (push)


十一、推送代码

git push

或首次推送:

git push -u origin main


十二、常见问题说明

  1. 如果 ssh 连接失败:
    检查是否执行 ssh -T git@github.com 测试成功

  2. 如果提示 Permission denied:
    说明 SSH Key 没加到 GitHub 或 ssh-agent 未加载

  3. 如果 push 失败:
    确认 remote 是否已从 https 改为 git@github.com


结束
SSH 配置成功后,后续 push/pull 都无需再配置

.NET4.7.2 WPF桌面软件 免费无报毒高难度反编译防护全套方案


一、核心总原则

全程使用:

  • 免费工具

  • 原生代码防护

  • 无底层危险行为

彻底避免:

  • 反虚拟机

  • 内存拦截

  • 驱动级调试

  • 外层加壳

实现:

  • 零报毒

  • 高反编译难度

  • 免费商用级保护

适配:

  • Windows Defender

  • 360

  • 火绒

  • 主流安全软件


二、VS 编译优化(必须)

1、打开项目配置

进入:

项目属性 → 生成

2、关闭调试信息

取消:

定义 DEBUG 常量定义 TRACE 常量

3、开启优化

勾选:

优化代码

作用:

  • 删除冗余逻辑

  • 提高反编译难度

  • 降低可读性


4、关闭 PDB 调试信息

调试信息选择:

效果:

删除 PDB无法变量追踪无法源码定位

5、固定 CPU 架构

推荐:

x64

或:

x86

禁止:

Any CPU

作用:

  • 降低误报

  • 减少程序集特征


6、关闭 XML 注释

取消:

生成 XML 注释文件

7、高级设置

关闭:

JIT 调试托管调试代码跟踪

三、ConfuserEx 混淆配置(核心)

1、下载工具

GitHub:

https://github.com/yck1509/ConfuserEx

2、导入程序集

导入:

主程序 EXE所有 DLL

统一混淆。


3、必须开启

以下功能安全且不报毒:

名称混淆控制流混淆字符串加密常量混淆资源混淆引用隐藏死代码删除

4、必须关闭

以下功能容易误报:

AntiVMAntiDebug硬件断点检测内存保护进程 HookPE 压缩UPXNtAPI 劫持运行时自修复

5、混淆后效果

使用:

dnSpyILSpydotPeek

查看时:

变量乱码代码逻辑错乱字符串不可见方法名全部混淆

四、WPF 专属加固

1、禁止松散 XAML

WPF 默认:

XAML → 编译成 BAML

发布后:

无法直接读取界面源码

2、核心逻辑不要写 XAML

禁止:

<Button Visibility="{Binding IsVip}" />

核心逻辑放:

后台 C#

3、授权逻辑拆散

不要集中在:

一个类一个窗口一个方法

建议分散:

程序启动页面加载按钮点击功能调用

五、原生无毒防护代码

1、轻量反调试

using System.Diagnostics;public static bool IsBeingDebugged(){    return Debugger.IsAttached;}if (IsBeingDebugged()){    Environment.Exit(0);}

特点:

纯 .NET API无危险行为不会报毒

2、完整性校验

程序启动时:

校验 EXE Hash

如果:

被 dnSpy 修改被补丁篡改

则:

直接退出

3、敏感字符串拆分

错误写法:

string key = "123456789";

推荐写法:

char[] k1 = { '1', '2', '3' };char[] k2 = { '7', '8', '9' };string realKey = new string(k1) + "456" + new string(k2);

作用:

避免字符串搜索破解

六、标准化发布配置

1、填写程序集信息

进入:

项目属性 → 程序集信息

填写:

公司名称产品名称版本号版权

2、禁止外层加壳

不要使用:

UPXAspack免费压缩壳

原因:

误报率极高

3、推荐发布模式

选择:

依赖框架部署

优点:

体积小误报低特征干净

4、更换正规图标

不要:

默认空白图标

建议:

正规 ICO 图标

七、整体防护效果

小白破解者

基本直接放弃

普通逆向人员

需要数小时分析

专业逆向人员

仍可能破解。

但:

成本高维护难收益低

八、核心避坑总结

免费方案最佳组合

VS 编译优化+ConfuserEx+轻量原生校验

零报毒核心逻辑

只做:

静态代码混淆

不要做:

内存拦截驱动行为底层 Hook

严禁使用

VMProtect 试用版Themida各种小众免费壳

原因:

误报严重

九、与 Python 对比

.NET WPF:

免费方案防护强度远高于 Python

Python:

几乎无法真正防反编译

Git + GitHub 私人仓库完整使用指南

适用于 Windows 环境,配合 Visual Studio 2022 和 Visual Studio Code 使用。


一、安装 Git

1. 下载

前往官网下载安装包:

https://git-scm.com/download/win

选择:

64-bit Git for Windows Setup


2. 安装要点

安装过程中保持默认选项,注意以下两步:

  • Adjusting your PATH environment
    选择:
    Git from the command line and also from 3rd-party software

  • Choosing the default editor
    可以选择:
    Use Visual Studio Code as Git's default editor


3. 验证安装

安装完成后,关闭并重新打开终端(PowerShell / CMD / VS Code Terminal),执行:

git --version

看到类似:

git version 2.47.0.windows.1

即表示安装成功。


二、首次配置(只需执行一次)

# 设置用户名(填你的 GitHub 用户名)git config --global user.name "你的GitHub用户名"# 设置邮箱(填你的 GitHub 注册邮箱)git config --global user.email "你的GitHub邮箱"# 可选:设置默认分支名为 main(GitHub 默认)git config --global init.defaultBranch main# 可选:解决中文文件名显示乱码git config --global core.quotepath false

验证配置:

git config --global --list

三、在 GitHub 创建私人仓库

  1. 登录:https://github.com

  2. 点击右上角 + → New repository

  3. 填写信息:

  • Repository name:
    my-project

  • Description:
    可选填写项目描述

  • Visibility:
    选择 Private

  • 不要勾选:

    • Add a README file

    • .gitignore

    • Choose a license

  1. 点击 Create repository

  2. 复制仓库 HTTPS 地址,例如:

https://github.com/你的用户名/my-project.git

四、本地项目首次推送到 GitHub

在项目根目录打开终端,依次执行:

# 1. 初始化 Git 仓库git init# 2. 添加所有文件(.gitignore 中的文件会自动排除)git add .# 3. 检查即将提交的文件列表git status# 4. 首次提交git commit -m "初始提交"# 5. 关联远程仓库git remote add origin https://github.com/你的用户名/my-project.git# 6. 推送到 GitHubgit push -u origin main

首次推送时会弹出 GitHub 登录授权窗口,授权后后续一般无需重复登录。


五、日常开发工作流

命令行方式

# 查看当前改动git status# 查看具体改动内容git diff# 添加所有改动git add .# 或添加指定文件git add 路径/文件名# 提交git commit -m "修复了xxx问题"# 推送git push

拉取远程更新

如果另一台电脑也修改了代码:

git pull

六、在 VS Code 中使用 Git

VS Code 已内置 Git 支持。

基本操作

操作 方法
打开 Git 面板 左侧「源代码管理」或 Ctrl+Shift+G
暂存文件 文件旁点击 +
暂存全部 「更改」标题旁点击 +
提交 输入提交信息 → 点击 ✓
推送 底部状态栏同步图标
拉取 命令面板执行 Git: Pull
查看改动 点击文件进入 Diff 视图

推荐扩展

推荐安装:

  • Git Graph
    可视化查看分支和提交历史

  • GitLens
    查看作者、历史、行级追踪


七、在 Visual Studio 2022 中使用 Git

Visual Studio 2022 同样内置完整 Git 支持。


打开项目

方式一:

文件 → 打开 → 文件夹

方式二:

直接打开:

backend/ActivationApi/ActivationApi.sln

基本操作

操作 方法
Git Changes 窗口 Git → 提交或暂存
暂存文件 右键 → 暂存
暂存全部 点击“全部暂存”
提交 输入提交信息 → “全部提交”
推送 顶部 ↑ 按钮
拉取 Git → 拉取
查看历史 Git → 查看分支历史记录
切换分支 右下角分支名

注意事项

  • VS 2022 打开 .sln 后,Git 操作针对整个仓库

  • 前后端共用同一个 .git 仓库


八、两个 IDE 的协作方式

前端开发 → VS Code 打开 my-project 根目录后端开发 → VS 2022 打开 backend/ActivationApi/ActivationApi.slnGit 提交 → 任意 IDE 都可操作

建议:

  • VS Code 负责 Git 操作

  • VS 2022 专注后端开发与调试


九、常用 Git 命令速查表

基础命令

git statusgit add .git commit -m "提交信息"git pushgit pullgit log --oneline -10

撤销与回退

git checkout -- 文件名git reset HEAD 文件名git reset --soft HEAD~1git reset --hard HEAD~1

分支操作

git branchgit branch 分支名git checkout 分支名git checkout -b 分支名git merge 分支名git branch -d 分支名

远程操作

git remote -vgit remote set-url origin 新地址git push -u origin 分支名

查看信息

git diffgit diff --stagedgit log --oneline --graphgit blame 文件名

十、在新电脑上克隆项目

# 1. 克隆仓库git clone https://github.com/你的用户名/my-project.git# 2. 进入项目目录cd my-project# 3. 创建 .env 文件copy .env.example .env# 4. 安装前端依赖cd frontend/soybean-admin-mainpnpm install# 5. 恢复后端依赖cd ../../backend/ActivationApidotnet restore

十一、安全提醒

文件 是否入库 说明
.env 包含数据库密码等敏感信息
.env.example 配置模板
appsettings.Development.json 本地开发配置
node_modules/ 可重新安装
bin/ obj/ 编译产物
backend/publish/ 发布文件

敏感文件误上传处理

# 从 Git 追踪中移除git rm --cached .env# 提交git commit -m "移除敏感文件"# 推送git push

注意:

即使删除,Git 历史中仍可能存在旧内容,建议立即更换所有泄露的密码和密钥。


十二、常见问题

Q:推送时提示 rejected - non-fast-forward

git pull --rebasegit push

Q:拉取时出现合并冲突

冲突示例:

<<<<<<< HEAD你的改动=======远程改动>>>>>>> origin/main

处理步骤:

git add .git commit -m "解决合并冲突"git push

Q:忽略已被追踪的文件

git rm --cached 文件路径git commit -m "停止追踪文件"

Q:查看文件历史

git log --oneline 文件路径git show 提交哈希:文件路径

Q:VS Code 不显示 Git 信息

确认当前打开的是包含 .git 文件夹的根目录。

 

你是资深.NET架构师,请对以下C#代码和对应的前端交互部分代码做“有限且收敛”的代码审查。

【目标】
只找“会真实影响系统运行”的问题,而不是优化代码风格或理论最佳实践。

重要:优化结果输出到 problem.md   注意 problem.md  中已经存在的问题就不要再输出了,这个问题都是已经处理或者不用处理的。

---

【一、终止条件(最高优先级)】
如果代码满足以下全部条件,必须直接输出:
👉 当前代码无需要优化的核心问题(已达到中小型.NET系统合理实现水平)

判定标准:
1. 代码可以正确运行(无编译/运行错误)
2. 不存在可复现的业务逻辑错误
3. 不存在明显异常未处理导致流程中断
4. 不存在会产生错误数据的风险
5. 不存在明显性能瓶颈(实际场景,不是理论)
6. 前后端交互契约无明显错误(参数/返回值合理)

---

【二、允许输出的问题范围(必须同时满足)】
只有满足以下全部条件的问题才允许输出:

1. 是“真实问题”,不是建议
2. 当前代码“已经存在风险”,不是未来可能
3. 可以明确说明触发场景
4. 不修改会造成实际影响(错误 / 崩溃 / 脏数据 / 安全漏洞 / 性能问题)

---

【三、严格限制(违反直接丢弃)】
禁止输出以下内容:

❌ 代码风格 / 命名规范 / 注释建议  
❌ 可读性优化 / 重构建议 / 设计模式建议  
❌ “可以优化 / 建议 / 更优雅”类描述  
❌ 理论最佳实践(但当前代码没问题)  
❌ 未来扩展性问题(当前用不到)  
❌ 重复问题(换说法本质一样)  

---

【四、输出数量限制】
最多输出 5条(不是建议,是“问题”)
如果不足 5 条,按实际数量输出
如果 0 条,必须触发【终止条件】

---

【五、输出格式(强制)】

按严重程度排序(P0,P1,P2,P3)

每个问题必须包含:

【问题描述】
(具体问题是什么)

【触发场景】
(什么情况下会发生)

【实际影响】
(不修改会导致什么问题)

【修复建议】
(只给必要修改,不做扩展优化)

---

【六、反向校验(关键约束)】
每条问题必须满足:

👉 能明确回答:“如果不改,会发生什么实际问题?”

如果回答不了 → 删除该问题

---

【七、收益阈值(防止过度优化)】

如果优化收益:
- 无法量化
- 或实际影响极小(<5%)

👉 一律视为“无效优化”,禁止输出

---

【八、分析视角要求】

必须结合:
- Controller
- Service
- Repository
- DTO / Entity

-对应的前端交互

禁止只从后端逻辑自洽角度分析,必须模拟对应的前端调用行为进行判断,必须从“前后端交互契约”角度分析,而不是只看后端代码

---

【最终要求】

宁可不输出,也不要凑问题。
禁止为了回答而回答。

 

-------------------------------------------------------------------------------------------------------------------------

你是做过商业软件授权系统的工程师,只检查"激活码系统漏洞"。

 

【项目技术上下文(必须结合以下信息判断)】

- 后端:ASP.NET Core Web API,SqlSugar ORM,MySQL

- 激活流程:客户端明文上送 machineCode + licenseKey → 后端验证后写入激活状态

- 激活状态枚举:unused / used / frozen(字符串存库)

- 风控:per-key SemaphoreSlim 串行(键为 machineCode+softwareVersionId)

+ IP 滑动窗口限流(每分钟 5 次)

- 机器码:完全由客户端上送,服务端仅做字符串比对,无服务端签发或验证

- 激活后无持续在线校验;客户端本地保存激活状态(具体存储方式由客户端决定)

- 管理后台:JWT HttpOnly Cookie,单超管模式,激活码增删改查走独立管理接口

 

【终止条件】

没有可利用漏洞 → 仅输出:

👉 激活流程无明显漏洞

 

【攻击者能力边界(严格执行)】

✅ 允许:

- 浏览器 DevTools / 抓包(Charles、Fiddler、Burp Suite)

- 重放、篡改 HTTP 请求参数

- 修改前端本地存储 / Cookie(非 HttpOnly 部分)

- 并发脚本(多线程/异步批量请求)

- 自由构造合法 HTTP 请求体

 

❌ 不允许(以下手段涉及的攻击一律不输出):

- 反编译 / Hook / 调试客户端二进制

- 修改客户端运行时内存或执行流程

- 控制客户端本地校验逻辑

 

【重点检查方向】

 

一、激活码复用

- 同一 licenseKey 能否在不同 machineCode 上重复激活

- 状态写入后是否被严格校验(是否存在并发双花窗口)

 

二、机器码伪造

- machineCode 由客户端明文上送、服务端仅字符串比对——

攻击者能否通过抓包复制他人 machineCode + licenseKey 组合绕过绑定?

- 激活后再次使用相同 machineCode 能否重复激活(冥等性是否正确)

 

三、风控绕过

- IP 限流(5次/分钟)能否通过换 IP / 伪造 X-Forwarded-For 绕过

- Attempt 风控键为 machineCode+softwareVersionId:

能否通过随机伪造 machineCode 枚举 licenseKey(键碰撞规避冷却)

- 冷却计时器是否在并发请求下可被多次触发(重置竞争)

 

四、状态与接口漏洞

- 激活接口是否存在"客户端收到成功响应但服务端未落库"的幽灵激活

- 是否存在绕过激活接口直接使用软件的路径(后端是否有持续校验)

- 重置接口(/activationCode/reset)权限是否向匿名客户端开放

 

五、枚举与信息泄露

- 匿名接口是否可枚举软件名/版本 ID 用于构造批量激活请求

- 错误响应是否泄露激活码状态差异(unused vs frozen vs not found)

 

【每条漏洞必须包含】

1. 攻击路径:具体 HTTP 请求步骤(可操作,无需客户端逆向)

2. 攻击后果:盗版 / 无限激活 / 绕过绑定 / 暴破激活码 等

 

不同时满足以上两点的,一律不输出。

 

【过滤规则(严格执行)】

以下情况判定为"不是漏洞",不输出:

- 需要反编译 / Hook / 调试客户端才能触发

- 纯理论、无具体 HTTP 操作路径

- 仅在开发环境 / 本地调试下成立

- 说不出"第一步发什么请求"的假设性描述

 

【禁止输出】

❌ 优化建议

❌ 架构设计

❌ 安全方案推荐

❌ 加密算法讨论(除非已被直接绕过)

❌ "可能更安全"等模糊描述

 

【输出上限】最多 6 条,优先输出危害最高的。

-------------------------------------------------------------------------------------------------------------------------

你是资深 DevOps / Linux 运维工程师,正在审查本项目的 SERVER_SETUP.md(服务器首次部署初始化文档)。

结果输出到:@ANALYZE.md

你的目标只有两个:

1. 判断首次部署步骤是否合理,是否存在会导致部署失败、SSH 锁死、证书申请失败、Docker 起不来、Nginx 起不来、权限不生效的真实问题。

2. 检查文档里的 Linux 命令是否可直接执行,是否存在明显语法错误、缺少 sudo、顺序错误、与仓库实现不一致、与 docker-compose.yml / nginx.conf 冲突的问题。

 

审查范围限制:

- 只审查首次部署必须步骤,不要扩展到系统优化、性能调优、审美建议、风格建议。

- 只关注会影响“首次成功上线”的问题。

- 只给出可验证的具体问题,不要泛泛而谈。

 

停止条件:

- 当你已经完整检查完 SERVER_SETUP.md 的每个章节后停止。

- 当你连续两轮检查都没有发现新的 P1 / P2 问题时停止。

- 当你已经列出 1 个 P1 或最多 5 个总问题后停止,不要继续挖掘次要优化建议。

- 如果只剩下格式、措辞、命名、排版类建议,直接判定为“无需继续优化”,不要继续扩展。

 

输出要求:

- 先给最终结论:合理 / 基本合理但需修正 / 不建议直接作为首次部署手册。

- 再按严重级别列出问题:P1、P2、P3。

- 每个问题必须写清楚:具体章节、原因、执行后果、建议修改方式。

- 如果没有会影响首次部署的真实问题,明确写“未发现阻塞项,当前可以使用”。

- 不要无限输出优化建议;只输出与首次部署成功直接相关的内容。

 

结合本项目时要额外核对:

- docker-compose.yml 里的 mysql / backend / nginx / certbot 启动顺序

- nginx/nginx.conf 里的 80/443、证书路径、ACME challenge、反代路径

- README.md 中对首次部署顺序的说明是否与 SERVER_SETUP.md 一致

 

-------------------------------------------------------------------------------------------------------------------------

 

你是资深 DevOps / Linux 运维工程师,正在审查本项目的 README.md(项目部署总指南)。

结果输出到:ANALYZE.md

 

你的目标只有两个:

1. 判断 README.md 中描述的首次部署流程(第 1~5 节)是否自洽,步骤顺序是否正确,是否存在会导致**部署失败、证书申请失败、Nginx 无法启动、服务无法访问**的真实问题。

2. 检查文档里的命令和配置说明是否可直接执行,是否存在以下问题:

   - 明显语法错误或缺少必要参数

   - 与 `docker-compose.yml` 中定义的 profile / service 名称不一致

   - 与 `nginx/nginx.conf` 的实际路径、端口、指令不一致

   - 与 `SERVER_SETUP.md` 的初始化步骤前后矛盾

   - 与 `backend/publish/` 或 `frontend/dist/` 等实际目录结构不符

 

审查范围限制:

- 只审查会影响"首次成功上线"的步骤,不要审查第 8 节(生产注意事项)里的安全建议、HSTS 调优等非阻塞内容。

- 只关注会导致部署卡住或失败的问题,不要扩展到措辞、排版、命名风格建议。

- 只给出可验证的具体问题,不要泛泛而谈。

 

停止条件:

- 当你已经完整检查完 README.md 第 1~7 节、第 9 节、第 11 节(上线前清单)后停止。

- 当你连续两轮检查都没有发现新的 P1 / P2 问题时停止。

- 当你已经列出 1 个 P1 或最多 5 个总问题后停止,不要继续挖掘次要优化建议。

- 如果只剩下格式、措辞、命名、排版类建议,直接判定为"无需继续优化",不要继续扩展。

 

输出要求:

- 先给最终结论:合理 / 基本合理但需修正 / 不建议直接作为首次部署手册。

- 再按严重级别列出问题:P1、P2、P3。

- 每个问题必须写清楚:具体章节编号、原因、执行后果、建议修改方式。

- 如果没有会影响首次部署的真实问题,明确写"未发现阻塞项,当前可以使用"。

- 不要无限输出优化建议;只输出与首次部署成功直接相关的内容。

 

结合本项目时要额外核对:

- `docker-compose.yml` 中 `certbot-bootstrap`、`certbot-init` 是否真的通过 `--profile` 定义,以及 README 里的 `docker compose --profile certbot-bootstrap run --rm certbot-bootstrap` 命令是否与 compose 文件中的 service/profile 名称严格对应

- Section 5.2 的 3 步部署顺序(生成临时证书 → `docker compose up -d` → 申请正式证书 → reload nginx)是否与 `docker-compose.yml` 里服务的 `depends_on` 和启动依赖关系一致

- Section 7 关于 certbot 自动续期后"nginx 会自动检测证书文件变化并重新加载"的说法是否与 `docker-compose.yml` 中 certbot 服务的实际配置(是否有 `--deploy-hook` 或 reload 命令)一致

- Section 4 上传清单中要求上传 `backend/sql/init.sql` 但未列入清单——`docker-compose.yml` 是否挂载了该文件,缺失是否会导致 MySQL 初始化失败

- Section 11 上线前检查清单是否覆盖了 Section 5 所有必须步骤,是否与 `SERVER_SETUP.md` 的前置步骤对齐

 

-------------------------------------------------------------------------------------------------------------------------

你是资深 DevOps / Docker Compose 运维工程师,正在审查本项目的 docker-compose.yml。

结果输出到:ANALYZE.md

 

你的目标只有两个:

1. 判断 `docker-compose.yml` 中定义的服务编排是否自洽,依赖链、启动顺序、健康检查是否正确,是否存在会导致**容器启动失败、证书挂载失效、Nginx 无法引用证书、MySQL 初始化 SQL 不执行、信号续期机制不触发**的真实问题。

 

2. 检查各服务的配置是否可直接运行,是否存在以下问题:

   - `depends_on` 缺少 `condition: service_healthy`,导致上游服务未就绪时下游已启动

   - `profiles` 名称是否与 README.md 中 `docker compose --profile <name> run --rm <service>` 命令严格对应

   - `certbot-bootstrap` 生成的临时证书路径(`/etc/letsencrypt/live/${DOMAIN}/`)是否与 `nginx/nginx.conf` 中 `ssl_certificate` / `ssl_certificate_key` 引用路径完全一致

   - `certbot` 续期服务的 `--deploy-hook "touch /var/run/certbot-signals/reload-nginx"` 机制——宿主机上是否存在对应 cron 脚本监听该信号文件,`docker-compose.yml` 本身是否对 nginx 容器有任何 reload 触发手段,还是完全依赖外部 cron

   - `nginx` 服务使用 `./nginx/nginx.conf:/etc/nginx/templates/default.conf.template:ro` 挂载,官方 nginx 镜像 `envsubst` 模板机制要求启动命令不能覆盖默认 entrypoint——当前 `command: ["nginx", "-g", "daemon off;"]` 是否会跳过 `/docker-entrypoint.d/` 导致模板变量 `${DOMAIN}` 未被替换

   - `mysql` 挂载了 `./backend/sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro`,若宿主机该文件不存在或路径有误,MySQL 初始化是否会静默跳过或报错

   - `letsencrypt-lib` 卷在 `certbot` 和 `certbot-init` 中挂载,但 `certbot-bootstrap` 中未挂载——是否影响 certbot 后续正常运行

   - 环境变量 `${DOMAIN}`、`${CERTBOT_EMAIL}`、`${Jwt__Secret}` 等是否在 `.env` 中有对应定义,缺失时容器启动行为是否可预期

   - `certbot-init` 的 `depends_on: nginx` 未加 `condition: service_healthy`,nginx 本身也没有 healthcheck,certbot-init 触发时 nginx 的 `.well-known/acme-challenge` 路由是否已就绪

 

**审查范围限制:**

- 只审查会影响"首次成功上线"的配置,不审查日志驱动、资源限额、监控等非阻塞优化项。

- 只关注会导致容器启动失败或证书链断裂的问题,不扩展到镜像版本钉固、命名风格建议。

- 只给出可验证的具体问题,不泛泛而谈。

 

**核对时须与以下文件交叉验证:**

- `nginx/nginx.conf`:`ssl_certificate` / `ssl_certificate_key` 路径、`proxy_pass` 目标地址与端口、`location /.well-known/acme-challenge` 是否正确指向 `letsencrypt-www` 卷路径

- `README.md` 第 5 节:`docker compose --profile certbot-bootstrap run --rm certbot-bootstrap` 与 `docker compose --profile certbot-init run --rm certbot-init` 命令中的 profile 名称、service 名称是否与 `docker-compose.yml` 中 `profiles` 字段严格一致

- `SERVER_SETUP.md`:宿主机 cron 脚本是否与 `certbot` 服务的信号文件路径 `/var/run/certbot-signals/reload-nginx` 对齐,是否有对应 `docker exec nginx nginx -s reload` 步骤

- `.env`:所有 `${VAR}` 占位符是否在 `.env` 中均有定义,尤其是 `DOMAIN`、`CERTBOT_EMAIL`、`Jwt__Secret`、`Security__HmacSecret`、`Security__ClientSignSecret`

 

**停止条件:**

- 当你已完整检查完 `docker-compose.yml` 全部服务(mysql、backend、nginx、certbot、certbot-bootstrap、certbot-init)、volumes、networks 后停止。

- 当你连续两轮检查都没有发现新的 P1 / P2 问题时停止。

- 当你已列出 1 个 P1 或最多 5 个总问题后停止,不要继续挖掘次要优化建议。

- 如果只剩下镜像版本、命名、排版类建议,直接判定为"无需继续优化"。

 

**输出要求:**

- 先给最终结论:自洽可用 / 基本自洽但需修正 / 存在阻塞性问题不建议直接使用。

- 再按严重级别列出问题:P1、P2、P3。

- 每个问题必须写清楚:具体服务名 / 配置字段、根本原因、执行后果、建议修改方式。

- 如果没有会阻塞首次部署的真实问题,明确写"未发现阻塞项,当前可以使用"。

- 不要无限输出优化建议;只输出与首次部署成功直接相关的内容。

 

结合本项目时要额外核对:

- `docker-compose.yml` 中 `certbot-bootstrap`、`certbot-init` 是否真的通过 `--profile` 定义,以及 README 里的 `docker compose --profile certbot-bootstrap run --rm certbot-bootstrap` 命令是否与 compose 文件中的 service/profile 名称严格对应

- Section 5.2 的 3 步部署顺序(生成临时证书 → `docker compose up -d` → 申请正式证书 → reload nginx)是否与 `docker-compose.yml` 里服务的 `depends_on` 和启动依赖关系一致

- Section 7 关于 certbot 自动续期后"nginx 会自动检测证书文件变化并重新加载"的说法是否与 `docker-compose.yml` 中 certbot 服务的实际配置(是否有 `--deploy-hook` 或 reload 命令)一致

- Section 4 上传清单中要求上传 `backend/sql/init.sql` 但未列入清单——`docker-compose.yml` 是否挂载了该文件,缺失是否会导致 MySQL 初始化失败

- Section 11 上线前检查清单是否覆盖了 Section 5 所有必须步骤,是否与 `SERVER_SETUP.md` 的前置步骤对齐

-------------------------------------------------------------------------------------------------------------------------

你是资深 DevOps / Linux 运维工程师,正在审查本项目两个核心配置文件:`backend/Dockerfile`、`nginx/nginx.conf`。

## 结果输出到:ANALYZE.md

 

### 你的审查目标

判断这两个文件是否能在 `docker compose up` / `docker compose build` 后实际正常工作,是否存在会导致**构建失败、容器启动失败、运行时权限错误、Nginx 配置指令失效**的真实问题。

### 需要逐项核对的具体问题(按文件)

 

#### `backend/Dockerfile`

1. **`COPY publish/ ./`** 的 build context 是 `./backend`,即实际拷贝的是宿主机 `backend/publish/`。请核查 `backend/publish/` 目录是否真实存在,以及 `ENTRYPOINT ["dotnet", "ActivationApi.dll"]` 所指向的 DLL 文件是否在该目录下。

2. **非 root 用户 `appuser` 与挂载卷权限冲突**:`docker-compose.yml` 将宿主机 `./uploads` 挂载到容器 `/app/uploads`(`backend` service 下 `volumes: - ./uploads:/app/uploads`)。Docker bind mount 默认以 root 身份创建宿主目录,容器内 `appuser` 可能无写入权限,后端上传接口会在运行时报 `Permission denied`。请核查 Dockerfile 或 compose 文件中是否有对应的权限处理(如 `chown`、`user: "uid:gid"` 或 `chmod`)。

3. `ENV ASPNETCORE_URLS=http://+:8080` 与 `docker-compose.yml` 里 `environment: ASPNETCORE_URLS: http://+:8080` 重复定义,确认是否冲突(compose 环境变量会覆盖镜像内 ENV)。

 

#### `nginx/nginx.conf`

1. **`${DOMAIN}` 变量替换机制**:`docker-compose.yml` 将该文件挂载为 `/etc/nginx/templates/default.conf.template:ro`,Nginx 官方镜像启动时会自动对 `templates/` 目录内的文件执行 `envsubst` 并输出到 `conf.d/`。核对:

   - `nginx` service 的 `environment:` 中是否包含 `DOMAIN` 变量(已有 `DOMAIN: ${DOMAIN}`);

   - 若 `DOMAIN` 在宿主机 `.env` 文件中未定义或为空,`envsubst` 会将 `${DOMAIN}` 替换为空字符串,Nginx 会以空 `server_name` 启动,`ssl_certificate` 路径也变为 `/etc/letsencrypt/live//fullchain.pem`,导致 Nginx 启动失败。

2. **`limit_req_zone` 放在文件顶层(http 上下文)**:该文件被 include 进 Nginx 的 `conf.d/` 目录,而 `conf.d/` 内容是在 `http {}` 块内 include 的。`limit_req_zone` 只能出现在 `http {}` 上下文,放在文件顶层是**正确的**。请直接确认这一点,无需修改。

3. **`add_header` 继承断裂问题(P1 安全指令失效)**:Nginx 有明确规定——子 `location` 块若定义了任意 `add_header`,则**不继承父 server 块的任何 `add_header`**。当前配置中:

   - `location = /index.html` 自定义了 `add_header Cache-Control`,父 server 块的 `X-Frame-Options`、`X-Content-Type-Options`、`Strict-Transport-Security`、`Content-Security-Policy` 等安全头**全部不会出现在 index.html 响应中**;

   - `location ~* \.(?:css|js|mjs|map|jpg|jpeg|gif|png|ico|svg|webp|woff|woff2|ttf|eot)$` 自定义了 `add_header Cache-Control`,同样会导致安全头对所有静态资源响应缺失;

   - 唯一正确继承安全头的路径是 `location /`(无自定义 `add_header`)。

   - 修复方式:在 `location = /index.html` 和 `location ~* \.(css|js...)$` 块内**重复声明**所有需要的安全头,或将安全头提取到单独 include 片段。

4. **`location = /index.html` 使用 `try_files $uri =404`**:当前 root 为 `/usr/share/nginx/html`,若 `index.html` 由 `docker-compose.yml` 以 volume 挂载(`./frontend/dist:/usr/share/nginx/html:ro`),文件存在则正常;但若 `frontend/dist/` 目录在部署时为空或未构建,`try_files` 会返回 404 而不是兜底到某个错误页,这是预期行为,确认即可。

5. **`proxy_pass http://backend:8080`** 中 `backend` 为 docker-compose service 名称,需确认 nginx 与 backend 处于同一 docker network(均在 `app-network`,已满足)。

6. `client_max_body_size 210m` 仅在 443 的 server block 中定义,80 端口的 server block(用于 ACME challenge 和 301 跳转)没有此指令——这是合理的,无需修改。

 

### 停止条件

- 当你已完整检查上述所有核对点后停止。

- 当你连续两轮没有发现新的 P1 / P2 问题时停止。

- **不要扩展到 TLS 版本选择、gzip 调优、缓存策略等非阻塞优化建议。**

 

### 输出要求

- **先给最终结论**:合理 / 基本合理但需修正 / 不建议直接投产。

- 再按严重级别列出:**P1**(会导致构建/启动/运行失败)、**P2**(功能异常但不即时崩溃)、**P3**(轻微问题)。

- 每个问题须写明:具体文件 + 行号、根本原因、执行后果、建议修改方式。

- 若无阻塞项,明确写"未发现阻塞项,当前可以使用",不要继续扩展。

 

-------------------------------------------------------------------------------------------------------------------------

你是资深 DevOps / Linux 运维工程师,正在审查一个生产级 Docker 部署项目的以下五个文件:backend/Dockerfile、nginx/nginx.conf、docker-compose.yml、SERVER_SETUP.md、README.md。

 

结果输出到:ANALYZE.md

 

审查目标

 

判断这五个文件是否能在 docker compose up / docker compose build 后实际正常工作,以及部署文档是否存在会导致构建失败、容器启动失败、运行时权限错误、Nginx 配置指令失效或误导部署操作的真实问题。

 

需要逐项核对的具体问题(按文件)

 

backend/Dockerfile

 

1. COPY --chown=appuser:appgroup publish/ ./(第 14 行)的 build context 为 ./backend(由 docker-compose.yml 的 build.context: ./backend 确定),即实际拷贝的是宿主机 backend/publish/。请核查:backend/publish/ 目录是否真实存在;ENTRYPOINT ["dotnet", "ActivationApi.dll"](第 27 行)所引用的 DLL 是否位于该目录的根层(对应容器内 /app/ActivationApi.dll),而非子目录。若目录不存在,docker build 在此行直接失败;若 DLL 位于子目录,dotnet ActivationApi.dll 运行时报 file not found。

 

2. UID/GID 跨文件对齐核查:Dockerfile 第 11 行以 UID/GID 1001 创建 appuser;docker-compose.yml 中 uploads-init 服务(第 37 行)执行 chown 1001:1001 /app/uploads。两处数字是否完全一致?若不一致,backend 容器内 appuser 对 /app/uploads 的写入会在运行时报 Permission denied。

 

3. bind mount 覆盖镜像层 chown 的链路完整性:Dockerfile 第 18 行的 RUN mkdir -p /app/uploads && chown appuser:appgroup /app/uploads 以 root 身份写入镜像层;compose 部署时宿主机 ./uploads 以 bind mount 覆盖该路径,镜像层 chown 失效,宿主目录权限改由 uploads-init 容器负责。请核查:depends_on: uploads-init: condition: service_completed_successfully(docker-compose 第 50 行)确保 uploads-init 在 backend 启动前完成;uploads-init 只 chown 挂载点本身(非递归),后端以 UID 1001 自行创建的子目录天然属于自身,覆盖是否完整。

 

4. backend 缺少 HEALTHCHECK 导致 nginx 提前代理:docker-compose.yml 中 nginx 的 depends_on: - backend(第 109–110 行)为 service_started 语义,即 backend 容器进程刚启动即触发 nginx 启动,不等待 .NET 应用就绪。若后端初始化耗时(数据库建连/Warmup),期间 /api/* 请求返回 502。请评估是否需要补充 Dockerfile HEALTHCHECK + compose service_healthy 条件,或确认短暂 502 为可接受权衡。

 

5. ASPNETCORE_URLS 是否在 Dockerfile 与 compose 中重复定义:核查 Dockerfile 是否含 ENV ASPNETCORE_URLS=http://+:8080。若无,则 compose 第 53 行是唯一来源,无冲突;若有,compose 环境变量覆盖镜像 ENV,结果相同但属冗余。请确认实际情况。

 

nginx/nginx.conf

 

1. listen 443 ssl http2;(第 21 行)语法在 nginx 1.25.1+ 已弃用:nginx 1.25.1 起 http2 参数从 listen 迁移为独立指令 http2 on;。docker-compose.yml 使用 image: nginx:1.25-alpine,启动日志会输出 the "http2" parameter of the "listen" directive is deprecated 警告,容器仍可运行。请确认是否需要改为 listen 443 ssl; + http2 on; 以消除噪音(P3,不阻塞)。

 

2. ${DOMAIN} 变量替换的空值 P1 风险(第 7、22、29–30 行):该文件以 template 形式挂载(docker-compose 第 119 行),Nginx 官方镜像启动时执行 envsubst,DOMAIN 来源于 compose environment → 宿主机 .env。若 .env 中 DOMAIN 未定义或为空:server_name ; 不报错,但降级为默认 server;ssl_certificate /etc/letsencrypt/live//fullchain.pem(路径双斜杠)→ 证书文件不存在 → Nginx 启动失败;请确认 .env 是否有非空 DOMAIN,以及部署文档是否明确将其标为必填。

 

3. add_header 继承断裂的修复完整性验证(第 75–122 行):Nginx 规定子 location 块若含任意 add_header,则不继承父 server 块的安全头。请逐行核对以下两处是否完整重复了父 server 块(第 59–68 行)的全部 6 条安全头,且 always 修饰符保持一致:location = /index.html(第 75–84 行);location ~* \.(css|js...)$(第 111–122 行)。已知配置注释中已有说明(第 74、110 行),请确认实际指令内容与注释描述一致。

 

4. limit_req_zone(第 3 行)放在文件顶层的正确性:该文件被 include 进 nginx conf.d,而 conf.d 在 http {} 块内 include,故 limit_req_zone 实际处于 http {} 上下文——这是正确的。请直接确认,无需修改。

 

5. proxy_pass http://backend:8080(第 92 行)的网络可达性:nginx 与 backend 同属 app-network(docker-compose 第 129–130、72–73 行),Docker 内网 DNS 可解析 backend。请直接确认无阻塞项。

 

6. certbot 与 nginx 共享 letsencrypt-www volume 的挂载点一致性:certbot 服务(renew --webroot -w /var/www/certbot)和 nginx(letsencrypt-www:/var/www/certbot:ro)均通过同一 named volume 共享 ACME challenge 文件目录,certbot 容器也将同一 volume 挂载到 /var/www/certbot(compose 第 146 行)。请核查两侧挂载路径是否对齐,certbot 写入的 challenge 文件是否能被 nginx 的 acme challenge 路径正确提供服务。

 

docker-compose.yml

 

1. mysql:8.0 + --default-authentication-plugin=mysql_native_password(第 8 行)的弃用风险:该参数在 MySQL 8.0.34 起弃用,MySQL 9.0 中已移除。mysql:8.0 当前指向 8.0.41+,启动时输出 [Warning] 但不影响运行。请评估是否改为 --authentication_policy=mysql_native_password 或直接移除,并确认 SqlSugar/MySqlConnector 驱动与无该参数的 MySQL 8.0 默认认证方式兼容(P3)。

 

2. uploads-init 无 networks 字段(第 31–38 行)是否正确:该服务仅做 chown,不需要网络,缺省 networks 是正确的。restart: "no" 防止崩溃重启;但每次 docker compose up 都会重新创建并运行(chown 幂等,无副作用)。请直接确认这是预期设计。

 

3. certbot 服务 bind mount /var/run/certbot-signals(第 148 行)在 tmpfs 重启后的可靠性:Ubuntu 24.04 的 /var/run(即 /run)是 tmpfs,服务器重启后目录消失。重启后流程:Docker daemon 重建 certbot 容器时,bind mount 目标不存在 → Docker 自动在宿主机创建该目录(root 权限)→ 容器内 mkdir -p /var/run/certbot-signals(第 153 行)冗余但无害 → 信号写入链路恢复。请核查此链路是否可靠,并确认宿主机 cron 任务是否在服务器重启后也能自动恢复(crontab 条目持久,不受 tmpfs 影响)。

 

4. nginx 服务 depends_on: - backend 无健康条件(第 109–110 行):与 Dockerfile 第 4 条相同问题的 compose 侧。nginx 容器启动时机与 backend 健康状态脱钩,导致 warmup 期间 502。请与 Dockerfile 第 4 条一并评估修复方案。

 

5. certbot 服务依赖 nginx: condition: service_healthy(第 137–138 行),而 nginx healthcheck 使用 nc -z -w 3 127.0.0.1 80(第 124 行):nginx:1.25-alpine 基于 Alpine Linux,包含 busybox,busybox 内置 nc(netcat),该 healthcheck 命令可正常执行。请直接确认无阻塞项。

 

6. certbot-init 服务无 restart 字段(第 165–196 行):缺省为 "no",加上 profiles: [certbot-init] 门控和 README 中以 --rm 运行,该服务不会持久存在。请直接确认符合预期。

 

SERVER_SETUP.md

 

1. 个人敏感信息硬编码(第 38、72、100 行):文件中包含真实用户名 az102、服务器 IP 45.152.65.84、SSH 端口 14609(原始)和 18108(变更后)。其他部署者若直接复制命令,会因凭据不匹配而失败,或尝试连接文档作者的服务器。请将所有具体值替换为 your-username、server-ip、old-ssh-port、new-ssh-port 等占位符(P2)。

 

2. Docker 镜像加速地址为账号专属(第 281–282 行):daemon.json 示例中的 krb3008y.mirror.aliyuncs.com 是阿里云为特定账号单独分配的加速地址,具有账号归属。其他部署者若照抄此地址可能被拒绝,或占用文档作者的配额。建议替换为通用说明(请在阿里云容器镜像服务控制台获取专属加速地址),或仅保留无账号限制的通用镜像如 docker.m.daocloud.io(P2)。

 

3. Cron 任务信号文件在 tmpfs 重启后消失的文档说明缺失(第 344 行):宿主机 cron 命令 test -f /var/run/certbot-signals/reload-nginx && docker exec ... 依赖信号文件存在。服务器重启后 /var/run/certbot-signals/ 目录消失,test -f 直接返回 false,cron 静默跳过——逻辑正确(无信号无需 reload)。但文档未说明 tmpfs 特性,部署者手动检查该路径时会困惑“目录为何消失”。建议补充一行说明(P3)。

 

4. Cron 任务的短路保护逻辑(第 344 行):命令为 test -f signal-file && docker exec nginx nginx -s reload && rm -f signal-file。若 nginx -s reload 失败,rm -f 不执行,信号文件保留,下一分钟 cron 自动重试。这是正确的保护逻辑,请直接确认无需修改。

 

README.md

 

1. Section 5.2 步骤编号跳号错误(第 268、279、298 行):部署步骤标注为“步骤0”→“步骤1”→“步骤3”,跳过了“步骤2”。部署者顺序执行时会产生“步骤2 在哪里”的困惑,降低文档可信度。建议修正为连续编号(P2 文档错误)。

 

2. Section 2.0 环境变量表(第 157–159 行)中 VITE_SERVICE_BASE_URL / VITE_APP_TITLE 的定义位置说明不清:这两个变量是 Vite 构建时变量,应存放于 frontend/soybean-admin-main/.env.prod,而非根目录 .env(docker-compose.yml 不向任何 service 注入这两个变量)。表格将其与 MySQL/JWT 等运行时变量并列且标为“否(由前端环境文件覆盖)”,可能误导部署者将其写入根目录 .env 后发现不生效。建议在备注列明确指出“写入 frontend/soybean-admin-main/.env.prod,不写入根目录 .env”(P3)。

 

3. Section 9.4 测试证书删除指令依赖 certbot 常驻服务运行(第 516 行):命令 docker compose exec certbot certbot delete --cert-name 你的域名 要求常驻 certbot 服务(非 profile 门控)正在运行。若部署者在 docker compose down 后执行此命令,会因容器不存在而报错。建议补充前置提示:执行前确认 certbot 服务在线:docker compose ps certbot(P3)。

 

4. Section 4 Windows PowerShell 上传命令的通配符兼容性(第 219 行):scp -r -P port C:\...\my-project\* dev@server-ip:/opt/... 中的 * 通配符在 PowerShell 内置的 OpenSSH scp 中可能不被 shell 展开(取决于 OpenSSH 版本),导致 * 被当作字面量文件名而上传失败。建议改为指定完整目录路径并注明“或使用 FinalShell / WinSCP 图形工具”(P3)。

 

停止条件

 

当你已完整检查上述所有核对点后停止。

当你连续两轮没有发现新的 P1 / P2 问题时停止。

不要扩展到 TLS 版本选择、gzip 调优、缓存策略、CI/CD 流水线、监控告警等非阻塞优化建议。

 

输出要求

 

先给最终结论:合理 / 基本合理但需修正 / 不建议直接投产。

再按严重级别列出:P1(会导致构建/启动/运行失败)、P2(功能异常但不即时崩溃,或文档误导部署)、P3(轻微问题)。

每个问题须写明:具体文件 + 行号、根本原因、执行后果、建议修改方式。

若无阻塞项,明确写“未发现阻塞项,当前可以使用”,不要继续扩展。


-------------------------------------------------------------------------------------------------------------------------

 

 

 # Docker 部署可运行性审查提示词(项目定制版)

 

 你现在要审查的是一个基于 Docker Compose 的生产部署方案。你的任务**只判断这个部署教程和配置能否真实跑通**,只输出会真实影响系统运行的配置问题。

 

 ## 一、审查目标

 

 请交叉检查以下文件是否一致且可运行:

 

 - `SERVER_SETUP.md`

 - `README.md`

 - `docker-compose.yml`

 - `nginx/nginx.conf`

 - `backend/Dockerfile`

 

 必要时可结合仓库中的 `.env`、`frontend/dist/`、`backend/publish/`、`backend/sql/init.sql`、`backend/ActivationApi/ActivationApi/publish` 等实际部署依赖一起校验,但**不要扩展到无关模块**。

 

 ## 二、审查范围

 

 只允许输出以下类型的问题:

 

 - 会导致 `docker compose up -d --build` 失败

 - 会导致某个核心容器起不来或反复重启

 - 会导致 Nginx 无法加载配置、无法启动、无法反向代理或无法提供 HTTPS

 - 会导致后端容器启动后立即报错退出

 - 会导致数据库初始化失败、连接失败、证书申请失败、静态资源无法提供、上传目录不可写、前端无法访问 API

 

 如果某个点只是“最佳实践更好”“安全性更高”“性能可以优化”“文档表达不够优雅”,**一律不要输出**。

 

 ## 三、硬性过滤规则

 

 你必须严格执行以下规则:

 

 - **只报真问题**:必须能明确回答“如果不改,会发生什么实际故障?”

 - **不能靠猜**:没有明确证据就不要下结论

 - **不能输出优化项**:收益无法量化、影响极小、只属于风格/规范/最佳实践的,全部忽略

 - **不能重复**:同一根因不要拆成多个问题

 - **最多 5 条**:不是建议,是硬上限

 - **0 条时必须终止**:如果没有任何真实阻塞问题,直接输出“未发现会阻塞部署的真实问题”,并结束

 

 ## 四、优先级判断标准

 

 按以下严重程度排序:

 

 - **P0**:一定会让部署失败、容器起不来、或核心访问链路完全不可用

 - **P1**:高概率导致关键功能不可用,或在首次部署/证书签发/重启时必现失败

 - **P2**:在常见部署条件下会导致明显功能缺失或服务异常,但不一定完全无法启动

 - **P3**:只有在特定部署条件下才会触发,但一旦触发仍然会造成真实运行故障

 

 如果不是“会真实影响系统运行”的问题,不要上报。

 

 ## 五、必须重点检查的项目特有风险点

 

 ### 1)Nginx 配置能否直接启动

 

 - `nginx/nginx.conf` 是否符合 Nginx 语法

 - 是否存在 Nginx 不允许的写法,例如无效嵌套、错误的 `location` 结构、错误的模板变量、错误的证书路径、错误的静态目录

 - 是否会因为证书文件不存在而导致 Nginx 启动失败

 - 是否与 `docker-compose.yml` 的挂载路径完全一致

 

 ### 2)证书申请和首次启动链路是否闭环

 

 - `certbot-bootstrap`、`certbot-init`、`certbot`、`nginx` 的启动顺序是否正确

 - 是否存在 README 写了能跑,但 compose 实际跑不通的问题

 - 80/443 端口、`/.well-known/acme-challenge/`、证书卷挂载、reload 机制是否真正能闭环

 

 ### 3)后端容器是否能正常启动

 

 - `backend/Dockerfile` 中 `COPY publish/ ./` 是否和构建产物一致

 - `ENTRYPOINT` 指向的 DLL 是否真实存在

 - `ASPNETCORE_URLS`、暴露端口、容器内监听端口、Nginx 反代端口是否一致

 - 数据库连接字符串、环境变量名、挂载目录、权限是否会导致后端启动失败

 

 ### 4)前端静态资源是否真的能被 Nginx 提供

 

 - `frontend/dist/` 是否必须存在

 - README 的部署步骤是否明确要求先构建前端

 - Nginx 的静态站点根目录是否和 compose 挂载一致

 

 ### 5)文档与配置是否互相矛盾

 

 - `SERVER_SETUP.md`、`README.md`、`docker-compose.yml` 三者是否对端口、域名、证书、目录、执行顺序描述一致

 - 如果文档和配置冲突,以**会导致真实部署失败**的一方为准,输出问题

 

 ## 六、输出要求

 

 只允许输出 0~5 条问题,格式必须严格如下:

 

 ### P0 / P1 / P2 / P3

 

 【问题描述】

 (具体是什么问题,写清楚根因)

 

 【触发场景】

 (什么情况下会发生)

 

 【实际影响】

 (不修改会导致什么真实故障,必须可验证)

 

 【修复建议】

 (只写必要修改,不要扩展优化)

 

 ## 七、反向校验

 

 每条问题在写完后,必须再次自问一次:

 

 **“如果不改,这个项目到底会坏在哪里?”**

 

 如果答不出来,删除该问题,不要凑数。

 

 ## 八、当前项目的输出风格要求

 

 - 用中文输出

 - 结论要收敛、克制、只报真实阻塞项

 - 不要写空泛建议

 - 不要写“可优化”“建议改进”“最好”“更合理”这类内容,除非它会直接导致部署失败

 - 如果发现多条问题来自同一个根因,合并成一条

 

 ## 九、推荐的审查顺序

 

 1. 先看 `docker-compose.yml` 能不能把服务链拉起来

 2. 再看 `nginx/nginx.conf` 是否能正常解析并成功启动

 3. 再看 `backend/Dockerfile` 是否能让后端镜像跑起来

 4. 再看 `README.md` / `SERVER_SETUP.md` 的步骤是否真的可执行

 5. 最后做全链路交叉验证,确认端口、路径、卷、环境变量完全一致

 

 ## 十、补充约束

 

 - 只做“会真实影响系统运行”的审查

 - 不做代码风格审查

 - 不做理论最佳实践审查

 - 不做性能微优化审查

 - 不做与部署无关的业务缺陷审查

 - 输出前务必确认每条都能回答“如果不改会发生什么实际问题”

 

1.Controller 校验:前端传的参数「格式对不对、有没有传」Service 校验:这个参数「能不能用、业务合不合法」

1.请围绕最小改动、低侵入集成、后端成本极低、轻量级、UI 友好、灵活适配这 6 个核心点

2.针对这x个问题,先按原触发场景实际验证代码,再逐一明确回答以下问题,禁止脑补、禁止自圆其说:1. 问题是否真正解决;2. 原触发场景是否仍存在;3. 能否复现 bug?若仍能复现,请直接指出未修复的根因。如果已经解决,加删除线归档。

推荐工具:Putty、FinalShell(可视化SSH)

准备:项目项目目录结构

my-project/

├── backend/

│   ├── Dockerfile

│   └── publish/

├── frontend/

│   ├── Dockerfile

│   └── dist/

├── docker-compose.yml

├── .env

├── README.md

└── nginx/

    └── nginx.conf

然后发布前后端项目,注意配置环境改为生产模式

1. 使用root账户登入服务器,先修改密码,然后创建一个普通用户,给sudo权限

  • passwd root      修改root密码
  • adduser dev      创建dev用户 然后设置一个密码,默认信息不填直接entry
  • usermod -aG sudo dev   给sudo权限  ->  su - dev 切换为dev

2. 禁用密码认证,强制使用SSH密钥

  • ssh-keygen -t ed25519     生成 SSH 密钥对,执行后全程连按 3 次回车就行,默认保存位置如下
  • 本地公钥上传到服务器   type C:\Users\az102\.ssh\id_ed25519.pub | ssh -p 14609 dev@45.152.65.84 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh"
  • 修改SSH配置文件  /etc/ssh/sshd_config
    • #禁止 root登录 (最安全)
      PermitRootLogin no
    • #白名单:仅允许 dev 用户登录  AllowUsers dev
    • #禁止密码登录(只允许key)
      PasswordAuthentication no
    • #启用公钥认证(必须)
      PubkeyAuthentication yes
    • #禁止挑战响应认证 (防旁路)
      ChallengeResponseAuthentication no
    • 禁止键盘交互认证(新版本替代ChalLengeResponse)KbdInteractiveAuthentication no
    • #是否启用PAM
      UsePAM yes
  • 重启 SSH 服务使配置生效 sudo systemctl restart ssh
  • 新开一个终端,不要关闭当前连接  不提示输入密码就是成功了  ssh -p 14609 dev@45.152.65.84

3. 配置防火墙(UFW)

  • sudo ufw limit 18108/tcp   1.先放行新SSH端口(关键),并且限制连接频率(防爆破更强)
    sudo ufw allow 80/tcp          2. 再放行常用端口
    sudo ufw allow 443/tcp      
  • 3.设置默认策略
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
  • sudo nano /etc/ssh/sshd_config   4.修改SHH配置文件   Port 14609 ->  Port 18108
  • sudo systemctl restart sshd            5.重启SSH服务
  • ssh -p 18108 dev@45.152.65.84    6.关键:新开一个终端测试连接(不要断当前连接)
  • sudo ufw enable   7. 确认能连上之后,再启用防火墙
  • sudo ufw status  8.查看当前放行规则

4.设置更新系统安全补丁

  • sudo apt install unattended-upgrades -y     安装自动更新工具
  • sudo dpkg-reconfigure -plow unattended-upgrades  开启自动更新,只更系统级的安全漏洞补丁
  • 修改 /etc/apt/apt.conf.d/50unattended-upgrades         
  • Unattended-Upgrade::Allowed-Origins  中只保留   "${distro_id}:${distro_codename}-security";  其他注释

5.时区设置(影响日志/证书)+ Chrony 自动校时

  • sudo apt install chrony -y      按照 Chrony 自动校时
  • sudo timedatectl set-timezone Asia/Shanghai         设置时区
  • sudo systemctl enable --now chrony      「设置开机自启」 + 「立刻启动服务」
  • timedatectl      验证时间是否正确

6.安装基础工具(运维必备)

  • sudo apt install -y curl wget git vim unzip

7.开启Swap(小内存服务器必须 如果你是 1G / 2G 服务器)

  • # (1). 创建一个 2GB 大小的交换文件(快速创建,比传统命令快10倍) sudo fallocate -l 2G /swapfile
  • # (2). 设置权限:仅 root 能读写(安全必须!否则系统会警告) sudo chmod 600 /swapfile
  • # (3). 格式化为交换分区格式 sudo mkswap /swapfile
  • # (4). 立即启用 Swap(不用重启,立刻生效) sudo swapon /swapfile
  • # (5). 写入开机自动挂载配置 → **永久生效的核心!grep -q '/swapfile' /etc/fstab || echo '/swapfile none swap defaults 0 0' | sudo tee -a /etc/fstab
  • # (6). 确认是否配置成功   free -h
  • # (7). 查看 Swap 是否永久生效(核心,重启不丢失的关键) cat /etc/fstab
  • # (8). 优化Swap使用策略(永久生效+立即生效)
    • 物理内存用到 90% 才开始用 Swap(最适合小内存服务器)
    • echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf     
    • sudo sysctl -p
  • # (9).验证配置是否成功    cat /proc/sys/vm/swappiness    输出10

8. Fail2Ban(防爆破攻击)✅ 必装

  • sudo apt install fail2ban -y
    sudo systemctl enable fail2ban
    sudo systemctl start fail2ban
  • 新增配置  sudo nano /etc/fail2ban/jail.local    写入
    • [sshd]
      enabled = true
      port = 18108
      maxretry = 3
      findtime = 600
      bantime = 86400

  • # 1. 查看运行状态(显示 active(running) 就是成功) sudo systemctl status fail2ban
  • # 2. 查看已启用的防护规则(显示 sshd 就是SSH防护已开启) sudo fail2ban-client status

9. Ubuntu 安装 Docker & Docker Compose

  • 卸载旧版本(如果装过) 
    • sudo apt-get remove docker docker-engine docker.io containerd runc
  • 安装基础依赖 
    • sudo apt-get update
    • sudo apt-get install -y ca-certificates curl gnupg lsb-release
  • 添加 Docker 国内镜像源(关键)
    • sudo mkdir -p /etc/apt/keyrings
    • curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    • echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
      $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • 安装 Docker和Docker Compose    

    • sudo apt-get update

    • sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

  • 启动 Docker  和  containerd   

    • # 1. 设置 Docker 开机自启(重启服务器自动运行)

      • sudo systemctl enable docker

    • # 2. 设置 containerd 开机自启(必须配!)

      • sudo systemctl enable containerd

    • # 3. 先启动底层依赖 containerd

      • sudo systemctl start containerd

    • # 4. 再启动 Docker 服务

      • sudo systemctl start containerd

      • sudo systemctl start docker

  • 测试 Docker     

    • docker -v
  • 配置 Docker 国内镜像加速(阿里云镜像加速,只限阿里云服务器使用)

    • sudo mkdir -p /etc/docker                                            

    •  sudo nano /etc/docker/daemon.json              

    • {  "registry-mirrors": [    "https://krb3008y.mirror.aliyuncs.com",    "https://docker.m.daocloud.io"  ],  "log-driver": "json-file",  "log-opts": {    "max-size": "10m",    "max-file": "3"  },  "exec-opts": ["native.cgroupdriver=systemd"],  "live-restore": true}

       

  • 重启 Docker     

    • sudo systemctl daemon-reload         
    • sudo systemctl restart docker
  • 测试是否成功
    • sudo docker run hello-world
  • 设置 Docker 自动清理
    • crontab -e   打开定时任务编辑器
    • 0 3 * * 0 /usr/bin/docker system prune -f 在文件最后一行,粘贴这句话
    • crontab -l   验证是否设置成功

10. dev 用户未加入 docker 组

  • sudo usermod -aG docker dev     把当前用户加入 docker 组
  • newgrp docker 立即生效

10. 创建项目文件夹

  • mkdir -p /opt/docker/my-project-name

11. 进入项目目录 

  • cd /opt/docker/my-project-name

12. 上传项目到服务器

  • 使用 FinalShell 可视化上传(最直观)

13. 首次启动项目 

  • docker compose up -d --build

14. 修改了代码 / 修改了docker配置文件 / 修改了项目配置文件 / 重置环境,清空旧容器重新构建

  • docker compose down && docker compose up -d --build

推荐工具:Virtualbox、Ubuntu 、Putty、FinalShell(可视化SSH)

注意:本地部署 docker镜像问题,国内防火墙问题访问不了外网,需要配置国内镜像

准备:项目按目录结构

my-project/

├── backend/

│ ├── publish/

│ └── Dockerfile

├── frontend/

│ ├── dist/

│ ├── Dockerfile

│ └── nginx.conf

└── docker-compose.yml

然后发布前后端项目,注意配置环境改为生产模式

1.下载 VirtualBox : https://www.virtualbox.org/

2. 下载 ubuntu.iso 服务器版, 如 ubuntu-24.04.4-live-server-amd64.iso, 国内镜像: https://mirrors.aliyun.com/ubuntu-releases/

3. VirtualBox 创建 Ubuntu 虚拟机:

4. 打开 VirtualBox →新建虚拟机:

 

5. 启动虚拟机 → 安装 Ubuntu

6. 设置NAT网络 → 配置端口转发 → SSH 远程连接 → MySQL 数据库 → HTTP 网站

7. Ubuntu 安装 Docker & Docker Compose

  • 卸载旧版本(如果装过) sudo apt-get remove docker docker-engine docker.io containerd runc
  • 安装基础依赖 sudo apt-get update
                                sudo apt-get install -y ca-certificates curl gnupg lsb-release
  • 添加 Docker 国内镜像源(关键)

    sudo mkdir -p /etc/apt/keyrings

    curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

    echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

  • 安装 Docker和Docker Compose    sudo apt-get update
    sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

  • 启动 Docker        sudo systemctl start docker
                                    sudo systemctl enable docker

  • 测试  docker -v

  • 配置 Docker 国内镜像加速(非常重要)sudo mkdir -p /etc/docker
                                                                                   sudo nano /etc/docker/daemon.json              

  • { "registry-mirrors": [ "https://hub.mirrorify.net", "https://docker.1ms.run"] }

  • Ctrl + O → 按回车确认保存
  • Ctrl + X → 退出编辑器
  • 重启 Docker      sudo systemctl daemon-reload          sudo systemctl restart docker

  • 使用方式 docker compose  新方式
  • 测试是否成功 sudo docker run hello-world
  • 权限优化(不用每次 sudo) sudo usermod -aG docker $USER            后执行           newgrp docker

8. 上传项目到用户目录下 /home/你的用户名/项目  (本地测试),服务器推荐放到 /var/www/项目名

9. 进入项目目录 cd /home/test/my-project

10. 首次启动项目  docker compose up -d --build

11. 强制重新构建 + 重启: docker compose down && docker compose up -d --build

 

1.(推荐)虚拟机改为NAT模式(公网可访问)
2.确保启动 OpenSSH 服务,Linux 虚拟机放行防火墙22端口
3.先关闭虚拟机,设置虚拟机专家级,设置网络- 点击端口转发,【名称随意、协议TCP、主机IP留空、主机端口避免和宿主机现有端口冲突、子系统IP查询ip addr show、子系统端口22】
2026-03-24T10:57:04.png

4.测试 ssh 虚拟机用户名@127.0.0.1 -p 8022


1.虚拟机网络改为桥接模式,(公网访问不了,需要配置,暂时不清楚怎么配置)
2.执行 ip addr show
2026-03-24T07:44:47.png
3.192.168.1.105:虚拟机的 IP 地址 使用ssh工具连接就行 可以正常使用复制剪切

注意:这个ip地址是动态的
最简单方案:路由器绑定静态 IP(推荐)
1.先记好两个关键信息(从你刚才的截图里就能拿到):
-虚拟机 MAC 地址:08:00:27:a2:88:34
-想固定的 IP:192.168.1.105(就是你现在用的这个)
2.打开路由器管理页面
-一般在浏览器输入:192.168.1.1 或 192.168.0.1(看路由器底部标签)
-输入路由器管理员账号密码(也在路由器底部)
3.找到「IP/MAC 绑定」或「DHCP 静态分配」
-不同品牌叫法不一样,比如:
-TP-Link:应用管理 → DHCP 静态地址分配
-小米 / 红米:高级设置 → 局域网 → 静态 IP 分配
-华硕:LAN → DHCP 服务器 → 手动分配 IP
-新建一条规则:
--MAC 地址:填 08-00-27-a2-88-34
--IP 地址:填 192.168.1.105
-保存 / 应用
4重启虚拟机
-之后不管怎么重启,虚拟机都会一直拿到 192.168.1.105 这个 IP,再也不会变了 ✅

1.Anti Debug (anti debug):防调试,阻止程序被调试器调试。

2.Anti Dump (anti dump):防内存转储,防止程序集被内存抓取。

3.Anti IL Dasm (anti ildasm):防反编译,用特性标记模块阻止 ILDasm。

4.Anti Tamper (anti tamper):防篡改,确保程序集完整性。

5.✳Constants (constants):常量加密与压缩。

6.✳Control Flow (ctrl flow):控制流混淆,扰乱方法内代码执行顺序。

7.Protection Hardening (harden):增强保护代码,使破解更难。

8.Invalid Metadata (invalid metadata):添加无效元数据,干扰反编译器。

9.Reference Proxy (ref proxy):隐藏类型/方法/字段引用。

10.✳Resources (resources):资源加密与压缩。

11.Type Scrambler (typescramble):用泛型替换类型。

12.✳Name (rename):符号重命名,混淆类、方法、字段名称。

13.Watermarking (watermark):添加水印,标识程序集归属。

注意:WPF程序可以跳过 Resource 加密模块,因为 Resource 主要用于 UI 显示,本身通常不包含敏感信息。
目前旧的程序:项目如果使用了 ConfuserEx 混淆,JSON 序列化库(Newtonsoft.Json/System.Text.Json)出现属性名冲突错误,请帮我改为纯手动字符串构建 JSON,完全移除 JSON 库依赖。

创建软件管理模块的完整流程:

  1. 创建页面组件文件:
    主页面:/src/views/software/index.vue
    搜索组件:/src/views/software/modules/notice-search.vue
    新增/编辑抽屉:/src/views/software/modules/notice-operate-drawer.vue
  2. 添加相关API接口:
    src/service/api/system-manage.ts
  3. 添加类型定义
    src/typings/api.d.ts
  4. 添加国际化配置,注意配置路由名称的时候不用配置app.d.ts
    src\typings\app.d.ts
    src/locales/langs/zh-cn.ts
    src/locales/langs/en-us.ts

1.修改 .env.test 配置文件中 VITE_SERVICE_BASE_URL 和VITE_OTHER_SERVICE_BASE_URL, 记得带/api (这个文件是API跳转的基础URL)

2.修改 .env 文件中 VITE_HTTP_PROXY=Y 修改成Y:表示开启代理,在开发环境中,代理的主要作用是解决跨域问题,生产环境不建议开启,避免影响性能

3.修改 .env 文件中 VITE_SERVICE_SUCCESS_CODE 这里的成功状态码如果有很多个,可以用 , 分隔。
这个时候request请求需要改造支持多状态码,修改文件src\service-alova\request\index.ts 对应 createAlovaRequest 方法下的 isBackendSuccess

async isBackendSuccess(response) {
      const resp = response.clone();
      const data = await resp.json();
      // 获取成功状态码列表(从环境变量中获取并解析为数组)
      const successCodes = import.meta.env.VITE_SERVICE_SUCCESS_CODE.split(',').map(code => code.trim());
      // 检查后端返回的 code 是否在成功状态码列表中
      return successCodes.includes(String(data.code));
    }

4.修改api方法fetchLogin中的userName

export function fetchLogin(userName: string, password: string) {
  return alova.Post<Api.Auth.LoginToken>('/auth/login', { username: userName, password });
}

5.(1)修改api方法fetchGetUserInfo中api,GetUserInfo改GetCurrentUser

export function fetchGetUserInfo() {
  return alova.Get<Api.Auth.UserInfo>('/auth/getCurrentUser');
}
interface UserInfo {
      /** User ID (from backend: Id) */
      id: number;
      /** Username (from backend: Username) */
      username: string;      // 注意这里修改后,建议查询下 UserInfo. 或者 userInfo.
      /** User roles (from backend: Roles) */
      roles: string[];
      /** Button permissions (frontend specific) */
      buttons: string[];
    }

6.路径:src\store\modules\auth\index.ts 下的const userInfo: Api.Auth.UserInfo = reactive 修改, 查询下 UserInfo. 或者 userInfo. 修改userInfo.userName 为 userInfo.username

  const userInfo: Api.Auth.UserInfo = reactive({
    id: 0,
    username: '',
    roles: [],
    buttons: []
  });

注意:(1)由于 axios 和 alova 的错误处理机制不同,axios 版本:返回 { data, error } 结构,alova 版本:直接返回数据或抛出异常,路径: src\store\modules\auth\index.ts 修改 auth store 以适配 alova 的返回格式。(2) 默认开发环境使用mock,可以删除对应的mock文件, 改为 requestAdapter: adapterFetch()

当前页码:data.number,此为当前所在的页码,在你给出的示例中,其值是0。
每页条数:data.size,代表每页包含的数据条数,示例里该值为3。
总条数:data.totalElements,表示数据的总数量,示例中的值是11。

处理 number 后端传值 默认为0的问题

transformer: res => {
  const { content = [], number = 0, size = 10, totalElements = 0 } = res.data || {};

  // 确保页码从 1 开始
  const pageNum = number + 1;
  const pageSize = size > 0 ? size : 10;

  const recordsWithIndex = content.map((item, index) => ({
    ...item,
    index: (pageNum - 1) * pageSize + index + 1
  }));

  return {
    data: recordsWithIndex,
    pageNum,
    pageSize,
    total: totalElements
  };
}

1.修改 .env.test 配置文件中 VITE_SERVICE_BASE_URL 和VITE_OTHER_SERVICE_BASE_URL, 记得带/api (这个文件是API跳转的基础URL)

2.修改 .env 文件中 VITE_SERVICE_SUCCESS_CODE 这里的成功状态码如果有很多个,可以用 , 分隔。
这个时候request请求需要改造支持多状态码,修改文件src\service\request\index.ts 对应 createFlatRequest 方法下的 isBackendSuccess

isBackendSuccess(response) {
  // 获取成功状态码列表(从环境变量中获取并解析为数组)
  const successCodes = (import.meta.env.VITE_SERVICE_SUCCESS_CODE || "").split(",").map((code) => code.trim());

  // 检查后端返回的 code 是否在成功状态码列表中
  return successCodes.includes(String(response.data.code));
}

3.修改api方法fetchGetUserInfo中api, getUserInfo改getCurrentUser

interface UserInfo {
      /** User ID (from backend: Id) */
      id: number;
      /** Username (from backend: Username) */
      userName: string; 
      /** User roles (from backend: Roles) */
      roles: string[];
      /** Button permissions (frontend specific) */
      buttons: string[];
    }

4.路径:src\store\modules\auth\index.ts 下的const userInfo: Api.Auth.UserInfo = reactive 修改, 查询下 UserInfo. 或者 userInfo. 有些字段修改一下

  const userInfo: Api.Auth.UserInfo = reactive({
    id: 0,
    userName: '',
    roles: [],
    buttons: []
  });

  1. Lombok Plugin:通过注解自动生成 getter、setter、toString、equals 等方法,减少 boilerplate 代码。
  2. SequenceDiagram:用于生成 序列图(Sequence Diagram)。它可以帮助开发者以图形化的方式展示类、方法和对象之间的交互,特别适用于描述系统内部的通信和协作流程。
  3. Swagger : 非插件,帮助开发者设计、构建、记录和使用 RESTful APIs。