Files
AI-Proxy-Worker/docs/Code-Style.md
2025-08-17 19:59:10 +08:00

589 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 代码风格指南
<div align="center">
**🌍 Language / 语言**
[🇺🇸 English](./Code-Style.en.md) | [🇨🇳 中文](./Code-Style.md)
</div>
本指南概述了 AI Proxy Worker 项目的编码标准和最佳实践。遵循这些准则确保整个项目的代码一致性、可维护性和可读性。
## 📋 通用原则
### 代码质量标准
- **可读性优先**:编写能讲述故事的代码
- **一致性**:在整个代码库中遵循既定模式
- **简洁性**:优先选择简单的解决方案而非复杂的
- **模块化设计**:拆分复杂函数为单一职责的小函数
- **低认知复杂度**保持函数的认知复杂度在15以下
- **性能**:考虑代码的性能影响
- **安全性**:在实现中始终优先考虑安全性
### 文件组织
```
ai-proxy-worker/
├── worker.js # 主要 worker 脚本
├── wrangler.toml # 配置文件
├── docs/ # 文档
├── examples/ # 使用示例
└── tests/ # 测试文件(未来)
```
## 🔧 JavaScript/TypeScript 标准
### 代码格式化
- **缩进**:使用 2 个空格(不使用制表符)
- **行长度**:每行最多 100 个字符
- **分号**:可选,但要保持一致
- **引号**:字符串使用单引号
- **尾随逗号**:在多行对象/数组中使用尾随逗号
```javascript
// ✅ 好的示例
const config = {
apiUrl: 'https://api.deepseek.com',
timeout: 30000,
retries: 3,
}
const models = [
'deepseek-chat',
'deepseek-reasoner',
]
// ❌ 避免这样写
const config = {
"apiUrl": "https://api.deepseek.com",
"timeout": 30000,
"retries": 3
};
```
### 命名约定
#### 变量和函数
变量和函数使用 camelCase
```javascript
// ✅ 好的示例
const apiResponse = await fetchData()
const userMessage = request.body.message
const isValidRequest = validateInput(data)
function processUserRequest(request) {
// 实现
}
async function sendUpstreamRequest(payload) {
// 实现
}
// ❌ 避免这样写
const api_response = await fetchData()
const user_message = request.body.message
const IsValidRequest = validateInput(data)
function ProcessUserRequest(request) {
// 实现
}
```
#### 常量
常量使用 UPPER_SNAKE_CASE
```javascript
// ✅ 好的示例
const API_BASE_URL = 'https://api.deepseek.com'
const DEFAULT_TIMEOUT = 30000
const MAX_RETRIES = 3
const SUPPORTED_MODELS = ['deepseek-chat', 'deepseek-reasoner']
// ❌ 避免这样写
const apiBaseUrl = 'https://api.deepseek.com'
const defaultTimeout = 30000
```
#### 类和对象
类和构造函数使用 PascalCase
```javascript
// ✅ 好的示例
class RequestHandler {
constructor(config) {
this.config = config
}
}
class ApiError extends Error {
constructor(message, statusCode) {
super(message)
this.statusCode = statusCode
}
}
// ❌ 避免这样写
class requestHandler {
// 实现
}
```
### 函数结构
#### 函数声明
短函数优先使用箭头函数,复杂逻辑使用常规函数:
```javascript
// ✅ 好的示例 - 短工具函数
const isValidModel = (model) => SUPPORTED_MODELS.includes(model)
const createErrorResponse = (message, status = 400) =>
new Response(JSON.stringify({ error: message }), { status })
// ✅ 好的示例 - 复杂函数
async function handleChatRequest(request, env) {
try {
// 验证请求
const validation = await validateRequest(request)
if (!validation.valid) {
return createErrorResponse(validation.error, 400)
}
// 处理请求
const response = await processChat(request, env)
return response
} catch (error) {
console.error('聊天请求失败:', error)
return createErrorResponse('内部服务器错误', 500)
}
}
```
#### 参数处理
对象参数使用解构:
```javascript
// ✅ 好的示例
async function processChat({ messages, model, temperature }, env) {
// 实现
}
// 带验证的替代方案
async function processChat(params, env) {
const { messages, model, temperature = 0.7 } = params
// 验证必需参数
if (!messages || !model) {
throw new Error('缺少必需参数')
}
// 实现
}
// ❌ 避免这样写
async function processChat(params, env) {
const messages = params.messages
const model = params.model
const temperature = params.temperature
// 实现
}
```
## 📝 文档标准
### JSDoc 注释
函数文档使用 JSDoc
```javascript
/**
* 向上游 API 发送聊天请求
* @param {Object} request - 聊天请求对象
* @param {Array} request.messages - 聊天消息数组
* @param {string} request.model - 要使用的模型
* @param {number} [request.temperature=0.7] - 采样温度
* @param {Object} env - 环境变量
* @param {string} env.DEEPSEEK_API_KEY - DeepSeek API 密钥
* @returns {Promise<Response>} API 响应
* @throws {Error} 当 API 密钥缺失或请求失败时
*/
async function sendChatRequest(request, env) {
// 实现
}
```
### 行内注释
使用注释解释复杂逻辑:
```javascript
// ✅ 好的示例 - 解释"为什么"
async function handleRequest(request, env) {
// 提取客户端 IP 用于速率限制
const clientIP = request.headers.get('CF-Connecting-IP') ||
request.headers.get('X-Forwarded-For') ||
'unknown'
// 在处理昂贵操作之前检查速率限制
if (!await checkRateLimit(clientIP)) {
return new Response('超出速率限制', { status: 429 })
}
// 处理实际请求
return await processRequest(request, env)
}
// ❌ 避免这样写 - 陈述显而易见的事实
async function handleRequest(request, env) {
// 获取客户端 IP
const clientIP = request.headers.get('CF-Connecting-IP')
// 返回速率限制响应
if (!await checkRateLimit(clientIP)) {
return new Response('超出速率限制', { status: 429 })
}
}
```
## 🔧 模块化验证架构
### 验证函数设计原则
本项目采用模块化验证架构,将复杂的验证逻辑拆分为多个单一职责的函数:
```javascript
// ✅ 好的示例 - 模块化验证
async function validateRequest(request) {
validateContentType(request); // 验证Content-Type
validateContentLength(request); // 验证请求大小
if (CONFIG.VALIDATE_REQUEST_BODY) {
await validateRequestBody(request); // 验证请求体
}
}
function validateContentType(request) {
const contentType = request.headers.get('content-type') || '';
if (!contentType.includes('application/json')) {
throw new Error('Invalid content type. Expected application/json');
}
}
async function validateRequestBody(request) {
try {
const body = await request.clone().json();
validateMessages(body.messages); // 验证消息数组
validateModel(body.model); // 验证模型
} catch (e) {
// 错误处理逻辑
}
}
```
### 函数复杂度控制
- **认知复杂度限制**: 每个函数保持认知复杂度 ≤ 15
- **单一职责原则**: 每个验证函数只负责一种验证
- **可组合性**: 验证函数可以独立测试和复用
```javascript
// ✅ 好的示例 - 单一职责
function validateSingleMessage(message) {
if (!message.role || !message.content) {
throw new Error('Invalid request format. Each message must have role and content');
}
if (!['system', 'user', 'assistant', 'tool'].includes(message.role)) {
throw new Error('Invalid request format. Invalid message role');
}
}
// ❌ 避免这样写 - 复杂的巨大函数
function validateEverything(request) {
// 100+ 行验证代码,认知复杂度 > 20
}
```
## 🛡️ 错误处理
### 错误响应格式
使用一致的错误响应格式:
```javascript
// ✅ 好的示例 - 一致的错误格式
function createErrorResponse(error, statusCode = 500, details = null) {
const errorResponse = {
error: error.code || 'unknown_error',
message: error.message || '发生意外错误',
timestamp: new Date().toISOString(),
}
// 在开发/调试模式下添加详细信息
if (details && env.DEBUG_MODE === 'true') {
errorResponse.details = details
}
return new Response(JSON.stringify(errorResponse), {
status: statusCode,
headers: { 'Content-Type': 'application/json' }
})
}
// 使用方法
try {
const result = await riskyOperation()
return new Response(JSON.stringify(result))
} catch (error) {
console.error('操作失败:', error)
return createErrorResponse(error, 500, { operation: 'riskyOperation' })
}
```
### 错误类型
为不同场景定义自定义错误类型:
```javascript
// ✅ 好的示例 - 自定义错误类
class ValidationError extends Error {
constructor(message, field = null) {
super(message)
this.name = 'ValidationError'
this.code = 'validation_error'
this.field = field
}
}
class ApiError extends Error {
constructor(message, statusCode = 500, originalError = null) {
super(message)
this.name = 'ApiError'
this.code = 'api_error'
this.statusCode = statusCode
this.originalError = originalError
}
}
// 使用方法
function validateChatRequest(data) {
if (!data.messages || !Array.isArray(data.messages)) {
throw new ValidationError('消息必须是数组', 'messages')
}
if (!data.model || typeof data.model !== 'string') {
throw new ValidationError('模型必须是字符串', 'model')
}
}
```
## 🔒 安全最佳实践
### 输入验证
始终验证和清理输入:
```javascript
// ✅ 好的示例 - 全面验证
function validateChatRequest(data) {
const errors = []
// 必需字段
if (!data.messages || !Array.isArray(data.messages)) {
errors.push('messages 必须是数组')
}
if (!data.model || typeof data.model !== 'string') {
errors.push('model 必须是字符串')
}
// 验证消息数组
if (data.messages) {
data.messages.forEach((msg, index) => {
if (!msg.role || !['user', 'assistant', 'system'].includes(msg.role)) {
errors.push(`messages[${index}].role 必须是 user、assistant 或 system`)
}
if (!msg.content || typeof msg.content !== 'string') {
errors.push(`messages[${index}].content 必须是非空字符串`)
}
// 内容长度限制
if (msg.content && msg.content.length > 100000) {
errors.push(`messages[${index}].content 超过最大长度`)
}
})
}
// 可选参数验证
if (data.temperature !== undefined) {
if (typeof data.temperature !== 'number' ||
data.temperature < 0 ||
data.temperature > 2) {
errors.push('temperature 必须是 0 到 2 之间的数字')
}
}
return {
valid: errors.length === 0,
errors
}
}
```
### 敏感数据处理
永远不要记录敏感信息:
```javascript
// ✅ 好的示例 - 清理后的日志
function logRequest(request, response) {
const logData = {
method: request.method,
url: new URL(request.url).pathname, // 不记录查询参数
status: response.status,
timestamp: new Date().toISOString(),
// 不记录授权头或正文内容
}
console.log('请求已处理:', logData)
}
// ❌ 避免这样写 - 记录敏感数据
function logRequest(request, response) {
console.log('请求:', {
headers: Object.fromEntries(request.headers), // 包含 API 密钥!
body: request.body, // 包含用户数据!
url: request.url // 可能包含敏感查询参数!
})
}
```
## ⚡ 性能指南
### Async/Await 最佳实践
正确使用 async/await
```javascript
// ✅ 好的示例 - 尽可能并行执行
async function processMultipleRequests(requests, env) {
// 并行执行请求
const promises = requests.map(request => processRequest(request, env))
const results = await Promise.allSettled(promises)
return results.map(result =>
result.status === 'fulfilled' ? result.value : null
).filter(Boolean)
}
// ✅ 好的示例 - 需要时顺序执行
async function processWithDependencies(request, env) {
const validation = await validateRequest(request)
if (!validation.valid) {
throw new ValidationError(validation.errors.join(', '))
}
const processed = await processRequest(request, env)
const logged = await logRequest(processed)
return processed
}
// ❌ 避免这样写 - 不必要的顺序执行
async function processMultipleRequests(requests, env) {
const results = []
for (const request of requests) {
const result = await processRequest(request, env) // 阻塞!
results.push(result)
}
return results
}
```
### 内存管理
注意内存使用:
```javascript
// ✅ 好的示例 - 清理资源
async function processLargeRequest(request, env) {
let reader = null
try {
reader = request.body.getReader()
const chunks = []
while (true) {
const { done, value } = await reader.read()
if (done) break
chunks.push(value)
}
return await processChunks(chunks)
} finally {
// 清理资源
if (reader) {
reader.releaseLock()
}
}
}
```
## 🧪 测试指南
### 测试结构
编写测试时(未来实现):
```javascript
// ✅ 好的示例 - 清晰的测试结构
describe('聊天请求处理器', () => {
describe('validateChatRequest', () => {
it('应该接受有效的聊天请求', () => {
const validRequest = {
messages: [{ role: 'user', content: '你好' }],
model: 'deepseek-chat'
}
const result = validateChatRequest(validRequest)
expect(result.valid).toBe(true)
})
it('应该拒绝没有消息的请求', () => {
const invalidRequest = { model: 'deepseek-chat' }
const result = validateChatRequest(invalidRequest)
expect(result.valid).toBe(false)
expect(result.errors).toContain('messages 必须是数组')
})
})
})
```
## 📋 代码审查清单
提交代码前,确保:
### 功能性
- [ ] 代码按预期工作
- [ ] 处理边界情况
- [ ] 正确管理错误条件
- [ ] 考虑性能影响
### 代码质量
- [ ] 遵循项目命名约定
- [ ] 函数大小合理(< 50
- [ ] 代码自文档化
- [ ] 复杂逻辑有注释
- [ ] 没有遗留调试代码
### 安全性
- [ ] 实现输入验证
- [ ] 日志中无敏感数据
- [ ] 适当的错误处理不泄露信息
- [ ] 适当设置安全头
### 文档
- [ ] 公共函数有 JSDoc 注释
- [ ] 需要时更新 README
- [ ] 为新功能提供示例
- [ ] 记录重大变更
---
**一致的代码风格让协作更容易**
遵循这些指南有助于维护高质量可维护的代码库让所有贡献者都能轻松使用