Dpz.Core.Web
Dpz.Core.Web 是 dpz.core 项目的核心 Web 前端/后端应用,基于 ASP.NET Core (.NET 11) 构建。它集成了丰富的功能,包括博客文章、动态、评论、实时聊天、身份验证等。
🛠 技术栈
后端
- 核心框架: .NET 11.0 (ASP.NET Core MVC)
- 数据库/缓存: MongoDB, Redis (StackExchange.Redis)
- 配置中心: AgileConfig
- 身份认证: OpenIddict (OAuth2/OIDC), JWT Bearer
- 后台任务: Hangfire
- 实时通信: SignalR (Redis Backplane)
- 响应式/设备检测: DeviceDetector.NET, Wangkanai.Detection, Wangkanai.Responsive
- 日志: Serilog
- Web 优化: WebMarkupMin (HTML/XML 压缩), Brotli/Gzip 压缩
- Markdown: Markdig
- 图片处理: SixLabors.ImageSharp
- 其他: AngleSharp (HTML 解析), HtmlSanitizer (安全清理), MailKit (邮件)
前端
- TypeScript - 类型安全的 JavaScript 超集
- esbuild - 超快速打包工具(< 50ms 增量编译)
- ESLint 9 + typescript-eslint - TS 代码质量检查(Flat Config)
- Prettier - 代码格式化
- ES Modules - 原生模块系统
- jQuery - DOM 操作和 AJAX
- SignalR - 实时通信客户端
✨ 功能特性
- 内容管理: 文章、动态 (Mumble)、评论、代码片段管理。
- 用户系统: 基于 Cookie 和 OpenIddict 的身份验证,支持第三方登录整合。
- 实时互动: 集成 SignalR 实现实时聊天、弹幕通知等功能。
- 设备适配: 自动检测设备类型(移动端/桌面端)并适配视图。
- 安全防护:
- IP 限流 (IpRateLimit)
- 爬虫/Bot 拦截 (RejectBotsMiddleware)
- 跨域资源共享 (CORS) 配置
- 性能优化:
- 响应式缓存 (ResponseCaching)
- 静态资源指纹/缓存控制
- HTML/XML 最小化
🚀 快速开始
前置要求
- .NET 11 SDK
- Node.js 18+ (用于构建前端资源)
- Redis Server
- Docker (可选,用于容器化部署)
本地开发
1. 初始化前端环境(首次运行)
# 初始化 TypeScript 和依赖
.\build.ps1 init
这会自动安装所有依赖并验证构建配置。 clean-css-cli 和 esbuild 均使用项目本地 npm 依赖,不需要全局安装。
2. 前端开发(Watch 模式)
# 启动主应用 watch(实时编译 TS/JS)
.\build.ps1 dev
# 兼容旧命令,同样启动主应用 watch
.\build.ps1 dev-all
# 代码检查与格式化
npm run lint
npm run format
在 watch 模式下,修改 .js 或 .ts 文件会自动重新编译(通常 < 50ms),刷新浏览器即可看到效果。
3. 运行 .NET 项目
配置 appsettings.json 中的 AgileConfig 连接:
{
"AgileConfig": {
"appId": "your-app-id",
"secret": "your-secret",
"nodes": "http://your-agile-config-server",
"env": "DEV"
}
}
启动项目:
dotnet run
访问 https://localhost:5001
4. 生产构建
# 完整构建(CSS + JS + 文件哈希)
.\build.ps1
# 或
.\build.ps1 build
构建流程:
- CSS 处理:
- 从
Views/Shared/_IncludeCssFilePartial.cshtml的 Development 段提取全局样式并合并压缩为global.min.css - 使用项目本地
node_modules/.bin/cleancss,不依赖全局clean-css-cli
- 从
- JavaScript 处理(esbuild):
- 构建主应用入口
- 生产模式输出带内容哈希的文件名(例如
app.min.[hash].js) - 主应用启用
splitting,输出scripts/chunks/*分包
- 文件哈希策略:
- CSS:由 PowerShell 使用 MD5(8位小写)重命名
- JS:由 esbuild 内置内容哈希(8位大写 Base32)输出
- 资源清单:
- esbuild 先产出
.app中间清单 build.ps1合并并写入wwwroot/assets-manifest.json- 运行时由
AssetService在非 Development 环境映射到带哈希路径
- esbuild 先产出
前端开发工作流
开发模式:
主应用(.\build.ps1 dev):
修改 wwwroot/scripts/**.js/.ts
-> esbuild watch 编译
-> 输出 wwwroot/scripts/app.dev.js + source map + dev chunks
兼容命令(.\build.ps1 dev-all):
- app: wwwroot/scripts/app.dev.js
构建脚本命令
.\build.ps1 help # 显示帮助
.\build.ps1 init # 初始化环境(安装依赖)
.\build.ps1 dev # 开发 watch(主应用)
.\build.ps1 dev-all # 开发 watch(兼容旧命令)
.\build.ps1 build # 生产构建(默认)
npm run lint # ESLint 检查 TS/TSX
npm run lint:fix # ESLint 自动修复
npm run format # Prettier 格式化 TS/TSX
npm run format:check # 检查格式
📈 压力测试 (k6)
压测脚本位于 loadtest/k6/,基于 k6 编写。脚本只请求动态页面与接口,不会解析 HTML 加载图片、样式、脚本等静态资源(这些资源在生产环境由 CDN 承载)。
运行场景
| 场景 | 说明 |
|---|---|
smoke | 单 VU 顺序访问全部页面,用于快速验证脚本与站点连通性 |
load | 常规负载(10 并发,1-3 秒思考间隔) |
stress | 阶梯加压到 100 并发(无思考间隔) |
spike | 10 秒内冲到 100 并发,验证突发流量 |
soak | 长时间稳定负载,观察内存与缓存 |
capacity | 按请求到达率阶梯加压(20/50/100/200/400 rps),用于寻找性能拐点 |
常用命令
# 本地开发:建议用 launchSettings 暴露的 http 端口,免去证书校验
k6 run -e BASE_URL=http://localhost:37702 -e SCENARIO=smoke src/Dpz.Core.Web/loadtest/k6/main.js
# 容量拐点测试:带实时 web 仪表盘,浏览器打开 http://127.0.0.1:5665
$env:K6_WEB_DASHBOARD = "true"
$env:K6_WEB_DASHBOARD_EXPORT = "capacity-report.html"
k6 run -e BASE_URL=http://localhost:37702 -e SCENARIO=capacity src/Dpz.Core.Web/loadtest/k6/main.js
# 使用 https 端口时需要跳过本地自签名证书校验
k6 run -e BASE_URL=https://localhost:37701 -e INSECURE_TLS=true -e SCENARIO=load src/Dpz.Core.Web/loadtest/k6/main.js
环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
BASE_URL | 必填 | 被测站点根地址 |
SCENARIO | load | 运行场景,见上表 |
INSECURE_TLS | false | 跳过 https 证书校验 |
ABORT_ON_FAIL | capacity 场景为 true | 失败率超阈值自动中止 |
DISCOVER_IDS | true | 自动从列表页抓取真实内容 ID |
DISCARD_BODIES | 压力场景为 true | 丢弃响应体以降低 k6 内存占用 |
SLEEP_MIN / SLEEP_MAX | 压力场景 0,其余 1/3 | 思考间隔秒数 |
CAPACITY_MAX_VUS | 500 | capacity 场景最大虚拟用户数 |
ARTICLE_IDS / MUMBLE_IDS / VIDEO_IDS / STEAM_IDS | 空 | 逗号分隔,手工指定内容 ID |
COOKIE | 空 | 登录态 Dpz.Web.Core.Authoriza 的值或完整 Cookie 头 |
P95_MS / P99_MS | 1500 / 3000 | 响应时间阈值(毫秒) |
ERROR_RATE | 0.01 | 失败率阈值 |
注意事项
- 不要手工传入不存在的内容 ID:站点对 404 有严格限流(5 分钟内 3 次即封禁 IP 30 分钟),脚本会在 setup 阶段自动从列表页抓取真实 ID
- 文章详情页会写库累加阅读量(Redis 计数器 + 5 秒批量落库),长时间压测会真实增加计数
- Debug 模式与 Rider 性能分析会显著拉低结果:容量测试建议使用
dotnet run -c Release并关闭性能分析 - 完整环境变量与实现说明见
loadtest/k6/main.js顶部注释
🐳 Docker 部署
生产发布统一走 Dpz.Core.Web.Jobs 的 Hangfire 发布流水线(/Pipeline/Index):先修改 Dpz.Core.Web.csproj 的 <Version>,再在页面勾选 DpzCore 触发,流水线会在构建机构建并推送镜像、在各部署机 docker pull 后重建容器。参见根目录 发布与部署 与 配置变更说明。
下面的命令仅用于手工构建/本地验证。
构建镜像
# 切换到解决方案根目录
cd /home/ubuntu/project/dpz.core/src
# 构建镜像
sudo docker build -t dpz.core -f Dpz.Core.Web/Dockerfile .
sudo docker build \
-t 127.0.0.1:3383/dpz.core:<version> \
-t 127.0.0.1:3383/dpz.core:latest \
-f Dpz.Core.Web/Dockerfile .
# 推送镜像
sudo docker push 127.0.0.1:3383/dpz.core:<version>
sudo docker push 127.0.0.1:3383/dpz.core:latest
镜像源
Dockerfile 里三个基础镜像都取自 mcr.microsoft.com(含前端构建阶段的 Node 24)。之所以不用 node:24-bookworm-slim,是因为国内构建机对 docker.io 的解析会被投毒,load metadata 阶段直接 dial tcp [2a03:2880:...]:443: i/o timeout,而 MCR 不受影响。前端阶段的 npm 默认走 registry.npmmirror.com。两者都可以用构建参数临时覆盖:
sudo docker build \
--build-arg NODE_IMAGE=node:24-bookworm-slim \
--build-arg NPM_REGISTRY=https://registry.npmjs.org \
-t dpz.core -f Dpz.Core.Web/Dockerfile .
如果构建机已经配好 Docker Hub 加速,也可以把加速源拉到本地再打回原标签,然后配合 --build-arg NODE_IMAGE=node:24-bookworm-slim 使用本地已有镜像,避免依赖任何公网镜像源:
sudo docker pull docker.m.daocloud.io/library/node:24-bookworm-slim
sudo docker tag docker.m.daocloud.io/library/node:24-bookworm-slim node:24-bookworm-slim
运行容器
生产环境
sudo docker run --restart=always \
--name dpz.core \
-e TZ=Asia/Shanghai \
-p 2372:8080 \
-d registry.dpangzi.com/dpz.core:latest
预发布环境 (UAT)
sudo docker build -t dpz.core.uat -f Dpz.Core.Web/Dockerfile .
sudo docker run --restart=always \
--name dpz.core.uat \
-e "AgileConfig:env=STAGING" \
-e TZ=Asia/Shanghai \
-p 33801:8080 \
-d dpz.core.uat:latest
测试环境
sudo docker network create dpz.core # 如果需要
sudo docker build -t dpz.core.test -f Dpz.Core.Web/Dockerfile .
sudo docker run --restart=always \
--name dpz.core.test \
-e "AgileConfig:env=TEST" \
-e TZ=Asia/Shanghai \
-p 33803:8080 \
-d dpz.core.test:latest
⚙️ 配置说明
拦截规则 (InterceptRules)
项目支持通过配置定义请求拦截规则,用于防御爬虫和恶意请求。
{
"InterceptRules": [
{ "Type": "UserAgent", "Pattern": "*bot*" },
{ "Type": "ClientIp", "Pattern": "192.168.1.*" },
{ "Type": "Uri", "Pattern": "/admin/*" }
]
}
IIS Web.Config
如果使用 IIS 托管,项目包含预配置的 web.config 规则,主要用于文件扩展名过滤,确保安全性。
📂 项目结构
src/Dpz.Core.Web/
├── Controllers/ # MVC 控制器
├── Views/ # Razor 视图
├── wwwroot/ # 静态资源
│ ├── css/ # 样式文件
│ ├── scripts/ # JavaScript/TypeScript
│ │ ├── modules/ # 功能模块
│ └── assets-manifest.json # 资源清单(自动生成)
├── Middleware/ # 自定义中间件
├── Library/ # 辅助类库、TagHelpers
├── Models/ # 视图模型
├── esbuild/ # 前端构建配置
├── loadtest/ # k6 压测脚本
├── build.ps1 # 统一构建脚本
├── tsconfig.json # TypeScript 配置
├── package.json # Node.js 依赖
└── Program.cs # 应用入口
📚 相关文档
- 构建脚本帮助:
.\build.ps1 help
📝 许可证
Copyright © dpangzi.