folder
folder
folder-lib
folder
folder-class
folder
folder-views
folder-public
git
prettier
prettier
powershell
docker
visualstudio
eslint
nodejs
nodejs
csharp
tsconfig
csharp

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 环境映射到带哈希路径

前端开发工作流

开发模式:
主应用(.\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 并发(无思考间隔)
spike10 秒内冲到 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必填被测站点根地址
SCENARIOload运行场景,见上表
INSECURE_TLSfalse跳过 https 证书校验
ABORT_ON_FAILcapacity 场景为 true失败率超阈值自动中止
DISCOVER_IDStrue自动从列表页抓取真实内容 ID
DISCARD_BODIES压力场景为 true丢弃响应体以降低 k6 内存占用
SLEEP_MIN / SLEEP_MAX压力场景 0,其余 1/3思考间隔秒数
CAPACITY_MAX_VUS500capacity 场景最大虚拟用户数
ARTICLE_IDS / MUMBLE_IDS / VIDEO_IDS / STEAM_IDS空逗号分隔,手工指定内容 ID
COOKIE空登录态 Dpz.Web.Core.Authoriza 的值或完整 Cookie 头
P95_MS / P99_MS1500 / 3000响应时间阈值(毫秒)
ERROR_RATE0.01失败率阈值

注意事项

  1. 不要手工传入不存在的内容 ID:站点对 404 有严格限流(5 分钟内 3 次即封禁 IP 30 分钟),脚本会在 setup 阶段自动从列表页抓取真实 ID
  2. 文章详情页会写库累加阅读量(Redis 计数器 + 5 秒批量落库),长时间压测会真实增加计数
  3. Debug 模式与 Rider 性能分析会显著拉低结果:容量测试建议使用 dotnet run -c Release 并关闭性能分析
  4. 完整环境变量与实现说明见 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.

评论加载中...