Handler的签名如下,本质是一个对HandlerData处理的IO函数。

1
2
3
4
5
6
7
8
9
10
data HandlerData child site = HandlerData
{ handlerRequest :: !YesodRequest
, handlerEnv :: !(RunHandlerEnv child site)
, handlerState :: !(IORef GHState)
, handlerResource :: !InternalState
}

newtype HandlerFor site a = HandlerFor
{ unHandlerFor :: HandlerData site site -> IO a
}

site是项目的配置,对site提供路由等实现。

Claude Flow 入门指南

🚀 Claude Flow v2.0.0-alpha - 企业级AI代理编排平台,让开发更智能、更高效!

📋 目录


🚀 快速开始

第1步:初始化项目

1
2
3
npm init -y
# 启动MCP服务器,让Claude能够协调多个AI代理
npx claude-flow@alpha mcp start

第2步:开发功能 (推荐TDD)

1
2
# 一条命令完成从需求到代码的全流程
npx claude-flow sparc tdd "用户注册功能"

第3步:查看结果

1
2
3
ls src/         # 查看源码
npm test # 运行测试
npm run build # 构建项目

🎯 基本命令

5个最常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 查看所有可用模式
npx claude-flow sparc modes

# 2. 运行TDD完整流程 (最推荐)
npx claude-flow sparc tdd "创建用户登录功能"

# 3. 单独运行某个阶段
npx claude-flow sparc run architect "设计API架构"

# 4. 并行执行多个模式
npx claude-flow sparc batch spec-pseudocode,architect "构建支付系统"

# 5. 启动MCP协调服务器
npx claude-flow@alpha mcp start

MCP命令详解

npx claude-flow@alpha mcp start 的作用:

  • 启动协调服务器:让Claude能够管理多个AI代理
  • 建立通信桥梁:不同代理之间可以共享信息和协调工作
  • 内存管理:代理可以存储和检索共享知识
  • 任务编排:自动分配和监控复杂任务的执行

什么时候需要运行:

  • 第一次使用claude-flow时
  • 想要使用多代理协调功能时
  • 执行复杂的SPARC工作流时

🧪 TDD是什么

TDD = Test-Driven Development (测试驱动开发)

TDD的3个步骤:

  1. 🔴 Red - 先写测试 (测试失败,红色)
  2. 🟢 Green - 写代码让测试通过 (绿色)
  3. 🔵 Refactor - 优化代码 (保持测试通过)

为什么用TDD?

  • 代码质量高 - 有测试保障,不容易出bug
  • 需求清晰 - 先写测试,强迫你想清楚要做什么
  • 重构安全 - 改代码时有测试保护,不怕改坏
  • 文档作用 - 测试就是活的使用文档

传统开发 vs TDD

1
2
3
4
5
# 传统方式:
写代码 → 手动测试 → 发现bug → 修复 → 重复...

# TDD方式:
写测试 → 写代码 → 测试通过 → 重构 → 完成!

claude-flow中的TDD

npx claude-flow sparc tdd "功能描述" 会自动:

  1. 分析需求 (Specification)
  2. 设计算法 (Pseudocode)
  3. 架构设计 (Architecture)
  4. 写测试+代码 (Refinement)
  5. 集成完善 (Completion)

💻 实战Demo

🆕 Demo 1: 新建项目完整流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 创建新项目目录
mkdir my-new-app && cd my-new-app

# 2. 初始化项目
npm init -y

# 3. 启动MCP协调服务器 (只需运行一次)
npx claude-flow@alpha mcp start

# 4. 使用TDD开发新功能 (一条命令完成全流程)
npx claude-flow sparc tdd "创建用户注册和登录系统"

# 5. 查看生成的代码
ls src/ && npm test && npm run build

🔧 Demo 2: 修改现有项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 进入现有项目目录
cd existing-project

# 2. 启动MCP服务器 (如果还没启动)
npx claude-flow@alpha mcp start

# 3. 添加新功能到现有项目
npx claude-flow sparc tdd "添加支付功能到现有电商系统"

# 4. 只修改特定部分 (不用完整TDD)
npx claude-flow sparc run architect "重构用户认证模块"
npx claude-flow sparc run code "优化数据库查询性能"

# 5. 批量处理多个改进
npx claude-flow sparc batch architect,code,tester "升级API版本到v2"

🚀 Demo 3: 特定场景命令

1
2
3
4
5
6
7
8
9
10
11
# 只做架构设计 (不写代码)
npx claude-flow sparc run architect "设计微服务架构"

# 只写代码 (已有设计)
npx claude-flow sparc run code "实现用户管理API"

# 只写测试 (已有代码)
npx claude-flow sparc run tester "为现有功能添加单元测试"

# 代码审查和优化
npx claude-flow sparc run security-review "审查代码质量并提供改进建议"

🎯 所有模式详解

🏗️ 核心开发流程

  • 📋 spec-pseudocode - 需求分析,写项目规格和伪代码
  • 🏗️ architect - 架构设计,设计可扩展的模块化架构
  • 🧠 code - 核心编码,写干净高效的代码
  • 🧪 tdd - 测试驱动开发,先写测试再写代码

🔧 质量保障

  • 🪲 debug - 调试问题,排查运行时错误和逻辑问题
  • 🛡️ security-review - 安全审查,检查代码安全漏洞
  • 🧹 refinement-optimization-mode - 代码优化,重构和性能提升

📚 文档与集成

  • 📚 docs-writer - 写文档,生成清晰的使用说明
  • 🔗 integration - 系统集成,合并各模块成完整系统
  • 📈 post-deployment-monitoring-mode - 部署监控,观察线上系统表现

🚀 运维部署

  • 🚀 devops - 运维自动化,CI/CD和基础设施管理

🎓 专业工具

  • 🔐 supabase-admin - Supabase数据库专家
  • ♾️ mcp - MCP服务集成专家
  • ❓ ask - 任务指导,帮你选择合适的模式
  • 📘 tutorial - SPARC教学,学习完整开发流程
  • ⚡️ sparc - 工作流编排,分解复杂任务

💡 实用场景示例

1
2
3
4
5
6
7
8
9
10
11
12
13
# 🔍 不知道从哪开始?
npx claude-flow sparc run ask "我想做一个博客系统"

# 📋 分析需求 → 🏗️ 设计架构 → 🧠 写代码
npx claude-flow sparc run spec-pseudocode "用户注册登录功能"
npx claude-flow sparc run architect "微服务电商平台"
npx claude-flow sparc run code "实现用户管理API"

# 🪲 修复bug → 🛡️ 安全检查 → 📚 写文档 → 🚀 部署
npx claude-flow sparc run debug "登录后页面白屏"
npx claude-flow sparc run security-review "检查支付模块安全性"
npx claude-flow sparc run docs-writer "为API生成使用文档"
npx claude-flow sparc run devops "部署到AWS"

📊 分析报告查看

claude-flow执行完成后会生成详细的分析报告,帮你了解性能和成本。

4种报告类型

1. 性能报告 📈

1
2
3
4
5
6
7
8
# 查看24小时性能报告 (默认)
npx claude-flow@alpha analysis performance-report

# 查看7天详细报告
npx claude-flow@alpha analysis performance-report --timeframe 7d --format detailed

# 导出JSON格式报告
npx claude-flow@alpha analysis performance-report --format json

2. Token使用分析 💰

1
2
3
4
5
# 分析Token消耗和成本
npx claude-flow@alpha analysis token-usage --breakdown --cost-analysis

# 查看特定代理的Token使用
npx claude-flow@alpha analysis token-usage --agent coder

3. 性能瓶颈检测 🔍

1
2
3
4
5
# 检测系统瓶颈
npx claude-flow@alpha analysis bottleneck-detect --scope system

# 检测特定代理瓶颈
npx claude-flow@alpha analysis bottleneck-detect --scope agent --target coordinator-1

4. 查看执行状态 📋

1
2
3
4
5
# 查看系统整体状态
npx claude-flow@alpha status

# 查看Hive Mind指标
npx claude-flow@alpha hive-mind metrics

📁 报告文件位置

  • HTML报告: analysis-reports/performance-*.html (很有价值!)
  • 执行记录: coordination/orchestration/ 目录
  • 内存数据: memory/claude-flow-data.json

💡 完整分析流程

1
2
3
4
5
6
7
8
9
# 1. 执行开发任务
npx claude-flow@alpha sparc tdd "用户登录功能"

# 2. 查看详细报告
npx claude-flow@alpha analysis performance-report --format detailed
npx claude-flow@alpha analysis token-usage --breakdown

# 3. 如果有问题,检查具体瓶颈
npx claude-flow@alpha analysis bottleneck-detect --scope system

⚙️ 代码规范设置

claude-flow支持设置个人代码规范,让所有生成的代码都遵循你的风格,无需每次都提醒。

方法1: 修改CLAUDE.md配置文件 (推荐)

编辑项目根目录的 CLAUDE.md 文件,添加你的代码规范:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
## 代码风格与规范

### 编程语言规范
**JavaScript/TypeScript:**
- 使用 ESLint + Prettier
- 缩进: 2个空格, 字符串: 单引号, 分号: 必须添加
- 变量命名: camelCase, 函数命名: 动词开头
- 常量: UPPER_SNAKE_CASE

**Python:**
- 遵循 PEP 8, 缩进: 4个空格
- 变量命名: snake_case, 类名: PascalCase
- 最大行长: 88字符 (Black格式化)

### 项目结构规范
- 源码放在 `src/` 目录, 测试放在 `tests/` 目录
- 每个模块不超过500行代码
- 函数必须有JSDoc注释, 使用中文注释

### 安全规范
- 永远不要硬编码密钥, 敏感信息使用环境变量
- 输入验证和SQL注入防护

方法2: 使用配置命令设置

1
2
3
4
5
6
7
# 设置代码风格配置
npx claude-flow@alpha config set codeStyle.javascript.indent 2
npx claude-flow@alpha config set codeStyle.javascript.quotes "single"

# 设置项目结构偏好
npx claude-flow@alpha config set project.sourceDir "src"
npx claude-flow@alpha config set project.maxFileLines 500

方法3: 创建风格模板文件

1
2
3
4
5
6
7
8
9
10
mkdir -p .claude
cat > .claude/style-guide.md << 'EOF'
# 个人代码风格指南

## TypeScript/React规范
- 使用函数式组件 + Hooks
- Props接口以Props结尾: UserCardProps
- 自定义Hook以use开头: useUserData
- 组件文件名使用PascalCase: UserCard.tsx
EOF

💡 验证设置效果

1
2
3
# 生成代码测试风格
npx claude-flow@alpha sparc run code "创建一个用户列表组件"
# 检查生成的代码是否符合你设置的风格规范

🏗️ 项目信息配置

为了避免每次执行任务都要重新分析项目,可以在配置文件中预设项目的基本情况。

方法1: 在CLAUDE.md中设置项目信息 (推荐)

编辑 CLAUDE.md 文件,添加项目全局信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
## 项目基本信息

### 🎯 项目概述
- **项目名称**: 电商管理系统
- **业务领域**: 电子商务/零售
- **目标用户**: 商家管理员、客服人员
- **核心功能**: 商品管理、订单处理、用户管理、数据分析

### 🏗️ 技术架构
- **前端**: React 18 + TypeScript + Vite
- **后端**: Node.js + Express + TypeScript
- **数据库**: PostgreSQL + Redis (缓存)
- **部署**: Docker + AWS EC2

### 📁 目录结构
├── frontend/ # 前端项目
│ ├── src/components/ # 通用组件
│ ├── src/pages/ # 页面组件
│ └── tests/ # 前端测试
├── backend/ # 后端项目
│ ├── src/controllers/ # 控制器
│ ├── src/services/ # 业务逻辑
│ └── tests/ # 后端测试
├── shared/ # 共享代码
└── docs/ # 项目文档

### 💡 开发注意事项
- **数据安全**: 所有敏感数据必须加密存储
- **性能要求**: 页面加载时间 < 2秒,API响应 < 500ms
- **浏览器兼容**: 支持Chrome 90+, Safari 14+, Firefox 88+

### 📊 业务规则
- **订单状态**: 待付款 → 已付款 → 已发货 → 已完成
- **用户权限**: 超级管理员 > 管理员 > 普通用户

方法2: 创建项目配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir -p .claude
cat > .claude/project.json << 'EOF'
{
"project": {
"name": "电商管理系统",
"type": "full-stack-web",
"domain": "e-commerce"
},
"structure": {
"frontend": {"path": "./frontend", "framework": "react"},
"backend": {"path": "./backend", "framework": "express"}
},
"business": {
"modules": ["用户管理", "商品管理", "订单处理"],
"workflows": {
"订单流程": ["创建订单", "支付", "发货", "收货"]
}
}
}
EOF

💡 配置效果

1
2
3
4
5
6
7
# 执行任务时,AI会自动读取项目信息
npx claude-flow@alpha sparc run code "为商品管理模块添加批量导入功能"

# AI会自动了解:
# - 这是电商系统的商品管理模块
# - 需要放在正确的目录结构中
# - 遵循已设定的安全和性能规范

🔧 环境问题解决

🚨 WSL环境下无法运行Maven/测试时

问题: 在WSL中无法执行Windows的Maven,导致TDD无法完成测试阶段

解决方案: 使用SPARC但跳过测试阶段

1
2
3
4
5
6
7
8
9
10
11
# 方案1: 分步执行 (推荐)
npx claude-flow sparc run spec-pseudocode "用户登录功能"
npx claude-flow sparc run architect "用户登录功能"
npx claude-flow sparc run code "用户登录功能"
# 跳过 tester 阶段

# 方案2: 批量执行但排除测试
npx claude-flow sparc batch spec-pseudocode,architect,code "用户登录功能"

# 方案3: 只要代码实现 (最简单)
npx claude-flow sparc run code "根据需求实现用户登录功能的完整代码"

🎯 不同场景的最佳选择

环境 推荐命令 说明
完整开发环境 sparc tdd 完整TDD流程
WSL/受限环境 sparc batch spec-pseudocode,architect,code 跳过测试阶段
快速原型 sparc run code 直接编码

📁 文件管理详解

根据你的项目结构,以下是各文件的作用和管理建议:

🔧 可执行文件 (不要修改)

  • claude-flow - Linux/macOS CLI主程序
  • claude-flow.bat - Windows批处理文件
  • claude-flow.ps1 - PowerShell脚本
  • 说明: 这些是claude-flow的核心执行文件,不要手动修改

⚙️ 配置文件 (可以修改)

  • claude-flow.config.json ✅ - 系统配置文件,可调整最大代理数、执行策略等
  • CLAUDE.md ✅ - 项目指令和规范文档,强烈建议修改

📊 运行时数据 (自动生成,不要修改)

  • analysis-reports/*.html ⭐⭐⭐⭐⭐ - 性能报告HTML文件,很有价值,定期查看
  • coordination/ - 代理协调目录,存储多代理协调记录
  • memory/ - 持久化存储,代理学习和记忆数据

🎯 版本控制建议

✅ 提交到Git的文件

1
2
3
4
5
6
git add CLAUDE.md                    # 项目配置核心
git add claude-flow.config.json # 系统配置
git add docs/ # 文档目录
git add src/ # 源代码 (生成后)
git add tests/ # 测试文件 (生成后)
git add package.json # 项目依赖 (生成后)

❌ 添加到.gitignore的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Claude Flow 运行时文件
claude-flow
claude-flow.bat
claude-flow.ps1
coordination/
memory/
analysis-reports/
*.log

# 标准忽略
node_modules/
.env
dist/
build/

💡 文件管理关键提醒

  1. 只修改配置文件 - CLAUDE.mdclaude-flow.config.json
  2. 定期查看性能报告 - analysis-reports/*.html 了解性能和成本
  3. 不要删除运行时目录 - coordination/memory/ 让系统自动管理
  4. 备份重要配置 - 修改前先备份 CLAUDE.md

💡 实用小贴士

🎯 使用建议

  • 初学者首选: 用 sparc tdd 命令,自动完成所有阶段
  • WSL用户: 用 sparc batch spec-pseudocode,architect,code 替代 sparc tdd
  • 执行完成后记得查看分析报告,了解性能和成本
  • 设置好代码规范和项目信息,所有任务都会自动遵循

⚙️ 环境要求

  • Node.js版本: 需要18+
  • MCP服务: mcp start 只需要运行一次,除非重启终端
  • 任务描述: 使用中文描述,AI理解更准确

📊 成本控制

  • 定期查看 token-usage 报告控制成本
  • TDD让代码更可靠,初学者强烈推荐使用
  • 无法运行测试时,记得手动验证生成的代码功能

🚀 项目类型选择

  • 新项目: 用 sparc tdd
  • 现有项目: 用单独的 sparc run 命令
  • 快速验证: 用 sparc run code 直接生成代码

📞 获取帮助


🎉 恭喜!你已经掌握了Claude Flow的核心用法。现在开始你的AI驱动开发之旅吧!

数据字典存储于数据库中,好处是可以随时在后台管理系统中添加,前端也能通过一个字典接口查询不同的数据字典,缺点是写代码的时候不如枚举安全,因为该字典存在于数据库中,并没有通过编译器校验。

举个例子,审批流程的状态有“审核中-0”、“审核通过-1”、“审核不通过-2”,那么在审批通过接口中,只能这么写

1
2
3
4
5
6
public void checkPass(long id) {
Order order = findById(id);
if (order.getStatus() != 0) {
throw new ServiceException("非审核中");
}
}

建议是,对于需要动态添加,且程序不需要对该字典进行判断的字典可以配置在数据库中。

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

前言

最近在配置企业邮箱的SPF记录时遇到了一系列问题,相信很多新手都会有类似的疑问。本文记录了从理解SPF原理到成功配置的完整过程,希望能帮助到有同样困惑的朋友。

什么是SPF?为什么需要它?

SPF的定义

SPF(Sender Policy Framework)是电子邮件系统中发送方策略框架的缩写,是一个非常高效的垃圾邮件解决方案。

初学者的疑问:这不是多此一举吗?

刚开始我也有这个疑问,感觉邮件系统已经有发件人地址了,为什么还需要SPF验证?

问题的根源: 邮件协议本身没有身份验证机制,任何人都可以声称自己是任何邮箱地址。

举个具体例子:

假设你的公司域名是 company.com,没有SPF保护时:

  1. 坏人租用任意服务器(IP: 1.2.3.4)
  2. 配置邮件服务器,伪造发件人为 ceo@company.com
  3. 给你客户发邮件:”紧急!请立即转账到这个账户…”

客户收到邮件时看到:

  • 发件人:ceo@company.com ✅ 看起来是你们CEO
  • 客户无法判断这封邮件是真是假

SPF如何防范:

设置SPF记录后:

1
company.com TXT "v=spf1 ip4:10.20.30.40 -all"

当坏人从 1.2.3.4 发送伪造邮件时:

  1. 收件方邮件服务器检查SPF记录
  2. 发现 1.2.3.4 不在授权列表中
  3. 直接拒收或标记为垃圾邮件

常见疑问解答

疑问1:每个人的IP都不同,SPF怎么配置?

这是很多新手的困惑,实际上SPF主要针对服务器发送邮件的场景,不是个人日常发邮件。

个人日常发邮件的流程:

1
2
3
4
5
6
你在家用Outlook发QQ邮件:
你的电脑IP: 192.168.1.100 (家庭路由器分配)
↓ (通过SMTP协议连接)
腾讯邮件服务器IP: 14.17.22.1 (这个IP才重要)

收件人看到的发送IP: 14.17.22.1

所以SPF记录里配置的是邮件服务商的服务器IP,不是最终用户的IP。

疑问2:不同平台登录邮箱,发件服务器不一样吗?

这个观察很敏锐!但实际情况是:

发件服务器不是由登录平台决定的,而是由邮箱服务商决定的

以企业邮箱 user@example.com 为例:

  • 在手机APP登录 → 发件服务器:阿里云的SMTP服务器
  • 在网页版登录 → 发件服务器:阿里云的SMTP服务器
  • 在Outlook登录 → 发件服务器:阿里云的SMTP服务器
  • 在企业微信登录 → 发件服务器:阿里云的SMTP服务器

为什么有些APP不需要配置服务器,有些需要?

  • 专用邮箱APP(如QQ邮箱APP):内置了自家邮箱的服务器配置
  • 通用邮件客户端(如企业微信、Outlook):需要手动配置服务器地址

但最终结果都是连接到同样的SMTP服务器。

实际配置过程

配置场景

  • 企业邮箱:user@example.com
  • 邮箱服务商:阿里企业邮箱

正确的配置方法

配置位置:example.com 域名的DNS解析中添加

配置内容:

1
2
3
记录类型:TXT
主机记录:@
记录值:v=spf1 include:spf.qiye.aliyun.com -all

配置注意事项

  1. 配置域名是你的企业域名,不是阿里云的域名
  2. 授权对象是阿里云的SPF域名:spf.qiye.aliyun.com
  3. 一个域名只能有一条SPF记录

踩坑记录

错误配置1:混淆SMTP域名和SPF域名

错误配置:

1
v=spf1 include:smtp.qiye.aliyun.com include:smtp.mxhichina.com -all

正确配置:

1
v=spf1 include:spf.qiye.aliyun.com -all

区别说明:

  • SMTP域名:smtp.qiye.aliyun.com (用于客户端连接发邮件)
  • SPF域名:spf.qiye.aliyun.com (包含授权IP列表,用于SPF验证)

错误现象:Gmail拒收邮件

错误信息:

1
2
3
4
5
550 5.7.26 Your email has been blocked because the sender is unauthenticated.
Gmail requires all senders to authenticate with either SPF or DKIM.
Authentication results:
DKIM = did not pass
SPF [example.com] with ip: [47.90.198.4] = did not pass

原因: SPF配置错误,导致验证失败

验证方法

方法1:nslookup命令

1
nslookup -q=txt example.com 8.8.8.8

正确结果应该包含:

1
example.com   text = "v=spf1 include:spf.qiye.aliyun.com -all"

方法2:在线SPF检查工具

常见疑问:为什么ping不通spf.qiye.aliyun.com?

这很正常!SPF域名通常是不能ping通的:

  • spf.qiye.aliyun.com 只包含TXT记录,没有A记录(IP地址)
  • ping不通不意味着配置错误

最终解决方案

最终正确配置:

1
2
3
记录类型:TXT
主机记录:@
记录值:v=spf1 include:spf.qiye.aliyun.com -all

验证成功:

  • DNS查询能正确返回SPF记录
  • 发送邮件到Gmail等严格验证的邮箱服务商不再被拒收
  • 邮件送达率显著提升

总结

SPF配置看似简单,但新手容易在以下几个方面犯错:

  1. 不理解SPF的防护原理,觉得多此一举
  2. 混淆个人邮件和服务器邮件的发送场景
  3. 搞错SMTP域名和SPF域名
  4. 不知道如何正确验证配置

希望这篇文章能帮助大家避免这些坑,快速配置好SPF记录,提升邮件的送达率和安全性。

参考资料


最后更新:2025年11月16日

Docker 日志管理最佳实践

在生产环境中,Docker 容器日志管理是一个关键的运维环节。不当的日志配置可能导致磁盘空间耗尽,影响系统稳定性。本文将介绍 Docker 日志管理的最佳实践。

为什么需要日志管理?

常见问题

  • 磁盘空间耗尽:日志文件无限制增长,占满服务器磁盘
  • 性能影响:大量日志 I/O 操作影响应用性能
  • 调试困难:日志文件过大,难以快速定位问题
  • 存储成本:大量历史日志占用昂贵的存储资源

解决方案

通过 Docker Compose 的 logging 配置,可以有效控制日志的大小和保留策略。

基础配置

标准日志轮转配置

1
2
3
4
5
6
7
8
services:
app:
image: my-app:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

配置说明

  • driver: "json-file":使用 Docker 默认的 JSON 文件驱动
  • max-size: "10m":单个日志文件最大 10MB
  • max-file: "3":保留最近 3 个日志文件

计算存储使用量

1
2
总日志空间 = max-size × max-file
示例:10MB × 3 = 30MB(每个容器)

不同环境的配置策略

开发环境

1
2
3
4
5
6
# 开发环境 - 更详细的日志
logging:
driver: "json-file"
options:
max-size: "5m"
max-file: "2"

测试环境

1
2
3
4
5
6
# 测试环境 - 平衡的配置
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

生产环境

1
2
3
4
5
6
# 生产环境 - 更保守的配置
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"

高级日志驱动

Syslog 驱动

1
2
3
4
5
logging:
driver: "syslog"
options:
syslog-address: "tcp://log-server.example.com:514"
tag: "{{.ImageName}}/{{.Name}}/{{.ID}}"

无日志驱动(性能优先)

1
2
logging:
driver: "none"

⚠️ 注意:完全禁用日志,无法使用 docker logs 命令

日志聚合(ELK Stack)

1
2
3
4
5
logging:
driver: "fluentd"
options:
fluentd-address: "localhost:24224"
tag: "docker.{{.Name}}"

实战示例

微服务架构日志配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
version: '3.8'

services:
# 前端服务 - 较少日志
frontend:
image: nginx:alpine
logging:
driver: "json-file"
options:
max-size: "5m"
max-file: "2"

# 后端 API - 中等日志量
backend:
image: my-backend:latest
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "5"

# 数据库 - 重要日志
database:
image: mysql:8.0
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"

# 消息队列 - 大量日志
redis:
image: redis:alpine
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

全局默认配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# docker-compose.yml
version: '3.8'

# 全局默认日志配置
x-logging: &default-logging
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

services:
app1:
image: app1:latest
<<: *default-logging

app2:
image: app2:latest
<<: *default-logging
# 可以覆盖默认配置
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"

日志查看命令

基础查看

1
2
3
4
5
6
7
8
9
10
11
# 查看最近日志
docker logs container-name

# 实时跟踪日志
docker logs -f container-name

# 查看最近 100 行
docker logs --tail 100 container-name

# 查看指定时间范围
docker logs --since "2024-01-01T00:00:00" container-name

使用 Docker Compose

1
2
3
4
5
6
7
8
# 查看所有服务日志
docker-compose logs

# 查看特定服务日志
docker-compose logs backend

# 实时跟踪
docker-compose logs -f backend

监控和告警

磁盘空间监控

1
2
3
4
5
6
7
8
# 检查 Docker 占用的磁盘空间
docker system df

# 查看详细信息
docker system df -v

# 清理未使用的资源
docker system prune

日志文件位置

1
2
3
4
5
# Docker 日志文件位置
/var/lib/docker/containers/<container-id>/<container-id>-json.log

# 查看容器 ID
docker ps --format "table {{.Names}}\t{{.ID}}\t{{.Status}}"

最佳实践建议

1. 根据应用类型调整配置

  • Web 应用:10-20MB,3-5 个文件
  • 数据库:50-100MB,5-10 个文件
  • 消息队列:20-50MB,3-7 个文件
  • 批处理任务:5-10MB,2-3 个文件

2. 环境差异化配置

  • 开发:小文件,少保留(快速迭代)
  • 测试:中等配置(平衡性能和调试)
  • 生产:大文件,多保留(故障排查)

3. 应用层面优化

1
2
3
4
5
6
7
8
9
# Spring Boot 应用日志配置
logging:
level:
com.example: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
file:
max-size: 10MB
max-history: 30

4. 集中化日志管理

对于大规模部署,建议使用 ELK Stack 或类似解决方案:

1
2
3
4
5
logging:
driver: "fluentd"
options:
fluentd-address: "fluentd:24224"
tag: "docker.{{.Name}}"

性能影响

I/O 性能

  • JSON 文件驱动:中等 I/O 开销
  • Syslog 驱动:网络开销
  • None 驱动:无开销,但无法调试

存储性能

  • SSD:推荐用于日志存储
  • HDD:可能影响应用性能
  • 网络存储:注意延迟影响

故障排查

常见问题

1. 日志轮转不工作

1
2
3
4
5
# 检查 Docker 版本
docker --version

# 重启 Docker 服务
sudo systemctl restart docker

2. 磁盘空间仍然不足

1
2
3
4
5
# 手动清理日志
truncate -s 0 /var/lib/docker/containers/*/*-json.log

# 或者使用 logrotate
sudo logrotate -f /etc/logrotate.conf

3. 无法查看日志

1
2
# 检查日志驱动配置
docker inspect container-name | grep -A 10 "LogConfig"

Docker 默认日志位置

不配置日志轮转的风险

如果不配置日志轮转,Docker 会将日志存储在默认位置,且没有大小限制 - 日志文件会无限增长直到磁盘空间耗尽。

默认日志文件位置

1
/var/lib/docker/containers/<container-id>/<container-id>-json.log

如何找到日志文件位置

方法一:获取容器 ID

1
2
3
4
5
# 列出容器及其 ID
docker ps

# 然后访问日志文件
/var/lib/docker/containers/abc123def456.../abc123def456...-json.log

方法二:使用 Docker Inspect

1
2
3
4
5
# 直接获取日志文件路径
docker inspect <container-name> | grep LogPath

# 示例输出:
"LogPath": "/var/lib/docker/containers/abc123def456.../abc123def456...-json.log"

方法三:使用 Find 命令

1
2
3
4
5
# 查找所有 Docker 日志文件
sudo find /var/lib/docker/containers -name "*-json.log"

# 查找特定容器的日志
sudo find /var/lib/docker/containers -name "*-json.log" | grep abc123

实际示例

1
2
3
4
5
6
7
8
9
10
# 运行中的容器
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123def456 nginx ... 1 hour Up 80:80 my-nginx

# 日志文件位置和大小
$ sudo ls -la /var/lib/docker/containers/abc123def456.../
-rw-r----- 1 root root 1048576000 Dec 28 10:30 abc123def456...-json.log

# 这个文件已经 1GB 了!(没有配置轮转)

查看默认日志

推荐方式(使用 Docker 命令):

1
2
docker logs my-nginx
docker logs -f my-nginx # 实时跟踪

直接文件访问(需要 root 权限):

1
sudo tail -f /var/lib/docker/containers/abc123def456.../abc123def456...-json.log

不配置日志轮转的危害

没有日志轮转配置时

  • ❌ 日志文件无限增长
  • ❌ 可能占满整个磁盘空间
  • ❌ 可能导致系统崩溃
  • ❌ 性能下降
  • ❌ 没有自动清理机制

失控日志的实际例子

1
2
3
4
5
6
$ sudo du -h /var/lib/docker/containers/*/
5.2G /var/lib/docker/containers/abc123def456.../
3.8G /var/lib/docker/containers/def789abc123.../
2.1G /var/lib/docker/containers/ghi456def789.../

# 总计:仅日志就占用了 11.1GB!

检查当前日志大小

1
2
3
4
5
6
7
8
9
10
11
# 检查所有容器日志大小
sudo du -sh /var/lib/docker/containers/*/

# 检查特定容器日志大小
sudo du -sh /var/lib/docker/containers/<container-id>/

# 检查 Docker 总空间使用情况
docker system df

# 详细信息
docker system df -v

紧急清理(磁盘空间不足时)

1
2
3
4
5
6
7
8
9
10
# 截断日志文件(保持容器运行)
sudo truncate -s 0 /var/lib/docker/containers/*/*-json.log

# 或者停止容器并删除日志
docker stop <container-name>
sudo rm /var/lib/docker/containers/<container-id>/*-json.log
docker start <container-name>

# 清理 Docker 系统
docker system prune -f

实时监控日志大小

1
2
3
4
5
6
7
8
# 监控脚本示例
#!/bin/bash
while true; do
echo "=== Docker 日志大小监控 $(date) ==="
sudo du -sh /var/lib/docker/containers/*/ | sort -hr | head -10
echo ""
sleep 300 # 每 5 分钟检查一次
done

日志文件格式

默认的 JSON 日志文件格式:

1
2
3
4
5
6
7
8
9
10
{
"log": "Hello World\n",
"stream": "stdout",
"time": "2024-01-01T10:30:00.123456789Z"
}
{
"log": "Error occurred\n",
"stream": "stderr",
"time": "2024-01-01T10:30:01.234567890Z"
}

总结

Docker 日志管理是生产环境运维的重要组成部分。通过合理的 logging 配置,可以:

  • ✅ 防止磁盘空间耗尽
  • ✅ 提高系统稳定性
  • ✅ 保留足够的调试信息
  • ✅ 优化存储成本

关键要点

  1. 默认位置/var/lib/docker/containers/<container-id>/<container-id>-json.log
  2. 无轮转配置:文件会无限增长直到磁盘满
  3. 生产环境:必须配置日志轮转
  4. 推荐使用docker logs 命令而非直接文件访问
  5. 定期监控:检查日志文件大小,防止磁盘空间问题

记住:没有日志轮转的生产环境是危险的!始终为你的 Docker 服务配置适当的日志管理策略。

最后的忠告:在生产环境中,永远不要让 Docker 容器在没有日志轮转配置的情况下长期运行。这是一个定时炸弹,迟早会导致系统故障!

Vue Dialog 组件封装的两种设计模式对比

在 Vue 开发中,我们经常需要使用 Dialog 来打开表单,这时候有两种主要的封装方式来组织这类组件:

  • 方式1:将 Dialog 和表单一起封装到一个组件里
  • 方式2:表单单独封装为组件,Dialog 放在父组件中

组件销毁策略

通常我们会在 Dialog 不展示的时候销毁其中的内容,可以通过在 Dialog 上添加 :close-on-click-modal="true" 来实现这一功能。

两种设计模式的详细对比

方式1:Dialog 和表单一体化封装

优点:

  • 高内聚性:所有相关逻辑都集中在一个组件中,便于理解和维护
  • 使用简便:调用时只需引入一个组件即可,API 简洁
  • 适用场景明确:特别适合该 Dialog 只在项目中单一场景使用的情况

缺点:

  • 复用性受限:表单逻辑与 Dialog 强耦合,无法在其他场景下单独复用
  • 组件体积偏大:职责不够单一,违反单一职责原则
  • 测试维护复杂:需要同时测试 Dialog 和表单逻辑,增加了测试复杂度

方式2:表单独立封装,Dialog 在父组件

优点:

  • 职责清晰分离:表单组件可以在不同展示容器中复用(Dialog、Drawer、页面等)
  • 组件灵活性高:表单可以独立进行测试、维护和迭代
  • 父组件控制力强:可以更灵活地控制 Dialog 的行为(打开/关闭时机、位置、动画效果等)

缺点:

  • 状态管理复杂:需要在父组件中管理更多状态(如 dialogVisible
  • 通信成本增加:组件间需要更多的 props 传递和事件处理
  • 使用门槛提升:使用时需要同时引入表单组件并管理 Dialog 状态

最佳实践推荐

选择方式1的场景:

  • 表单只在单一 Dialog 场景中使用
  • 业务逻辑相对简单
  • 项目规模较小,组件复用需求不强

选择方式2的场景:

  • 表单需要在多个地方复用
  • 项目规模较大,需要更好的组件解耦
  • 团队开发,需要明确的职责分工
  • 对组件测试和维护有较高要求

总结

两种封装方式各有其适用场景,关键在于根据具体的业务需求和项目特点来选择。在实际开发中,建议优先考虑组件的复用性和可维护性,当这些因素不是主要考虑点时,可以选择更简单直接的封装方式。

跨系统身份验证实施指南

第一部分:身份验证提供者系统(认证服务器)

作为认证中心,为其他系统提供统一登录服务并颁发安全令牌的核心系统。

系统流程



graph TD
    A[接收登录请求] --> B{是否有重定向参数?}
    B -->|是| C[存储重定向URL]
    B -->|否| D[使用默认重定向]

    C --> E[显示登录页面]
    D --> E

    E --> F[用户提交凭据]
    F --> G[后端验证]

    G --> H{有效?}
    H -->|否| I[显示错误]
    I --> E

    H -->|是| J[生成/存储令牌]
    J --> K{重定向URL存在?}

    K -->|是| L{是外部链接?}
    K -->|否| M[导航到仪表板]

    L -->|是| N[将令牌附加到URL]
    L -->|否| O[内部导航]

    N --> P[window.location.href重定向]
    O --> Q[router.push重定向]
    M --> R[结束]
    P --> R
    Q --> R

核心组件

1. 登录页面组件

  • 解析并存储URL查询参数中的重定向地址
  • 处理用户登录表单提交
  • 成功身份验证后执行以下操作:
    • 检索已存储的重定向URL
    • 判断重定向目标是内部页面还是外部系统
    • 携带令牌执行相应的重定向操作

2. 重定向工具模块

1
2
3
4
5
核心函数:
- parseRedirectUrl(): 从URL中解析重定向参数
- isExternalUrl(): 判断URL是否指向外部系统
- buildAuthenticatedUrl(): 将认证令牌附加到重定向URL
- performRedirect(): 执行页面重定向操作

3. 路由守卫

1
2
3
4
5
6
7
router.beforeEach 逻辑:
- 用户已认证且存在重定向参数时:
- 跳过登录页面显示
- 直接使用现有令牌执行重定向
- 用户未认证时:
- 允许正常访问登录页面
- 保持重定向参数不变

4. 令牌管理模块

  • 用户成功登录后安全存储认证令牌
  • 为重定向逻辑提供令牌获取接口
  • 处理令牌持久化存储(支持localStorage、sessionStorage、cookie等方式)

实施时序图



sequenceDiagram
    participant URL as 浏览器URL
    participant Login as 登录页面
    participant Auth as 认证服务
    participant Store as 令牌存储
    participant Redirect as 重定向处理器

    URL->>Login: 加载 ?redirect=targetUrl
    Login->>Login: 解析并存储重定向参数
    Login->>Auth: 提交凭据
    Auth->>Store: 保存令牌
    Auth->>Login: 返回成功
    Login->>Redirect: 使用存储的URL调用
    Redirect->>Redirect: 检查是否为外部链接
    Redirect->>Redirect: 使用令牌构建URL
    Redirect->>URL: 执行重定向


第二部分:客户端系统(接入认证的业务系统)

依赖认证提供者完成用户身份验证的业务应用系统。

系统流程



graph TD
    A[用户访问受保护路由] --> B{有有效令牌?}
    B -->|是| C[允许访问]
    B -->|否| D[构建认证提供者URL]

    D --> E[将当前URL编码为重定向参数]
    E --> F[重定向到认证提供者]

    F --> G[用户在认证提供者完成登录]
    G --> H[带令牌重定向回来]

    H --> I{URL中有令牌?}
    I -->|是| J[提取令牌]
    I -->|否| K[再次重定向到登录]

    J --> L[验证令牌]
    L --> M{有效?}
    M -->|是| N[本地存储令牌]
    M -->|否| K

    N --> O[从URL移除令牌]
    O --> P[继续到请求的页面]

    C --> Q[结束]
    P --> Q
    K --> Q

核心组件

1. 路由保护机制

1
2
3
4
5
6
7
8
9
10
11
router.beforeEach 守卫逻辑:
- 检查当前路由是否需要身份验证
- 验证用户现有令牌的有效性
- 无有效令牌时的处理:
- 将当前URL作为重定向参数构建认证提供者链接
- 跳转到认证提供者进行登录
- 从认证提供者返回时的处理:
- 从URL参数中提取认证令牌
- 将令牌存储到本地
- 清理URL中的敏感参数
- 继续用户原始导航请求

2. 令牌处理器模块

1
2
3
4
5
6
核心函数:
- extractTokenFromUrl(): 从URL查询参数中提取令牌
- validateToken(): 验证令牌格式和有效性
- storeToken(): 将令牌安全存储到本地
- cleanUrlParams(): 从浏览器URL中清除令牌参数
- hasValidToken(): 检查用户当前认证状态

3. 身份验证服务模块

  • 构建认证提供者的重定向URL链接
  • 处理令牌验证和刷新逻辑
  • 管理用户会话状态
  • 处理用户登出操作(清除本地令牌并重定向到登录页)

4. API请求拦截器

  • 自动将认证令牌附加到API请求头
  • 处理401未授权响应
  • 令牌失效时自动触发重新认证流程

认证返回流程处理



sequenceDiagram
    participant Browser as 浏览器
    participant Router as 路由守卫
    participant Token as 令牌处理器
    participant Storage as 本地存储
    participant Page as 受保护页面

    Browser->>Router: 从认证返回 ?token=xxx
    Router->>Token: 从URL提取令牌
    Token->>Token: 验证令牌格式
    Token->>Storage: 存储令牌
    Token->>Browser: 清理URL(移除令牌参数)
    Router->>Page: 允许访问受保护路由


系统间集成要点

认证提供者系统职责

  1. 参数接收:接受并解析来自客户端的重定向参数
  2. 身份验证:验证用户提供的登录凭据
  3. 令牌生成:生成安全的认证令牌
  4. URL构建:将令牌安全地附加到重定向URL
  5. 跨域重定向:执行安全的跨系统重定向操作

客户端系统职责

  1. 访问检测:识别并拦截未认证的受保护资源访问
  2. 重定向构建:构建包含返回地址的认证提供者URL
  3. 返回处理:处理来自认证提供者的回调请求
  4. 令牌管理:提取、验证并安全存储认证令牌
  5. 会话维护:维护用户的登录状态和会话信息

安全考虑要点

  • URL白名单:严格验证重定向目标URL,防止开放重定向攻击
  • HTTPS强制:所有认证相关的重定向必须使用HTTPS协议
  • 令牌生命周期:实现合理的令牌过期机制
  • 敏感数据清理:及时清理URL中的令牌等敏感信息
  • 令牌刷新:实现安全的令牌自动刷新机制
0%