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

14 KiB
Raw Blame History

代码风格指南

🌍 Language / 语言

🇺🇸 English | 🇨🇳 中文

本指南概述了 AI Proxy Worker 项目的编码标准和最佳实践。遵循这些准则确保整个项目的代码一致性、可维护性和可读性。

📋 通用原则

代码质量标准

  • 可读性优先:编写能讲述故事的代码
  • 一致性:在整个代码库中遵循既定模式
  • 简洁性:优先选择简单的解决方案而非复杂的
  • 模块化设计:拆分复杂函数为单一职责的小函数
  • 低认知复杂度保持函数的认知复杂度在15以下
  • 性能:考虑代码的性能影响
  • 安全性:在实现中始终优先考虑安全性

文件组织

ai-proxy-worker/
├── worker.js              # 主要 worker 脚本
├── wrangler.toml          # 配置文件
├── docs/                  # 文档
├── examples/              # 使用示例
└── tests/                 # 测试文件(未来)

🔧 JavaScript/TypeScript 标准

代码格式化

  • 缩进:使用 2 个空格(不使用制表符)
  • 行长度:每行最多 100 个字符
  • 分号:可选,但要保持一致
  • 引号:字符串使用单引号
  • 尾随逗号:在多行对象/数组中使用尾随逗号
// ✅ 好的示例
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

// ✅ 好的示例
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

// ✅ 好的示例
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

// ✅ 好的示例
class RequestHandler {
  constructor(config) {
    this.config = config
  }
}

class ApiError extends Error {
  constructor(message, statusCode) {
    super(message)
    this.statusCode = statusCode
  }
}

// ❌ 避免这样写
class requestHandler {
  // 实现
}

函数结构

函数声明

短函数优先使用箭头函数,复杂逻辑使用常规函数:

// ✅ 好的示例 - 短工具函数
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)
  }
}

参数处理

对象参数使用解构:

// ✅ 好的示例
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

/**
 * 向上游 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) {
  // 实现
}

行内注释

使用注释解释复杂逻辑:

// ✅ 好的示例 - 解释"为什么"
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 })
  }
}

🔧 模块化验证架构

验证函数设计原则

本项目采用模块化验证架构,将复杂的验证逻辑拆分为多个单一职责的函数:

// ✅ 好的示例 - 模块化验证
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
  • 单一职责原则: 每个验证函数只负责一种验证
  • 可组合性: 验证函数可以独立测试和复用
// ✅ 好的示例 - 单一职责
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
}

🛡️ 错误处理

错误响应格式

使用一致的错误响应格式:

// ✅ 好的示例 - 一致的错误格式
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' })
}

错误类型

为不同场景定义自定义错误类型:

// ✅ 好的示例 - 自定义错误类
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')
  }
}

🔒 安全最佳实践

输入验证

始终验证和清理输入:

// ✅ 好的示例 - 全面验证
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
  }
}

敏感数据处理

永远不要记录敏感信息:

// ✅ 好的示例 - 清理后的日志
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

// ✅ 好的示例 - 尽可能并行执行
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
}

内存管理

注意内存使用:

// ✅ 好的示例 - 清理资源
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()
    }
  }
}

🧪 测试指南

测试结构

编写测试时(未来实现):

// ✅ 好的示例 - 清晰的测试结构
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
  • 为新功能提供示例
  • 记录重大变更

一致的代码风格让协作更容易

遵循这些指南有助于维护高质量、可维护的代码库,让所有贡献者都能轻松使用。