Files
AI-Proxy-Worker/docs/Code-Style.md

589 lines
14 KiB
Markdown
Raw Permalink Normal View History

# 代码风格指南
<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
- [ ] 为新功能提供示例
- [ ] 记录重大变更
---
**一致的代码风格让协作更容易** ✨
遵循这些指南有助于维护高质量、可维护的代码库,让所有贡献者都能轻松使用。