概述

本文档详细介绍了 Xget 的安全机制和性能优化策略。通过多层安全防护和全面的性能优化,Xget 确保了服务的安全性、稳定性和高性能。

安全机制

请求验证

User-Agent 验证

Xget 对 User-Agent 进行严格验证,确保请求来自合法的客户端。

// User-Agent 白名单验证
const USER_AGENT_WHITELIST = [
  'git/',
  'curl/',
  'wget/',
  'aria2/',
  'npm/',
  'pip/',
  'docker/',
  'Mozilla/5.0',
  'Go-http-client/',
  'Java/',
  'Python-urllib/'
];

function validateUserAgent(userAgent) {
  if (!userAgent) {
    return false;
  }
  
  return USER_AGENT_WHITELIST.some(pattern => 
    userAgent.includes(pattern)
  );
}

配置示例

// 在环境变量中配置自定义 User-Agent 白名单
const CUSTOM_USER_AGENTS = process.env.CUSTOM_USER_AGENTS 
  ? process.env.CUSTOM_USER_AGENTS.split(',') 
  : [];

Referer 验证

验证请求来源,防止 CSRF 攻击。

// Referer 白名单验证
const REFERER_WHITELIST = [
  'https://github.com',
  'https://gitlab.com',
  'https://gitee.com',
  'https://pypi.org',
  'https://registry.npmjs.org'
];

function validateReferer(referer) {
  if (!referer) {
    return true; // 允许无 Referer 的请求
  }
  
  try {
    const refererUrl = new URL(referer);
    return REFERER_WHITELIST.some(allowed => 
      refererUrl.origin === allowed
    );
  } catch (error) {
    return false;
  }
}

IP 限流

基于 IP 的请求限流,防止滥用。

// IP 限流配置
const RATE_LIMIT_CONFIG = {
  windowMs: 60 * 1000, // 1 分钟
  maxRequests: 100,    // 每分钟最多 100 次请求
  skipSuccessfulRequests: true // 跳过成功的请求
};

// 使用 Cloudflare Workers KV 实现限流
async function checkRateLimit(ip) {
  const key = `ratelimit:${ip}`;
  const now = Date.now();
  
  const data = await KV.get(key, { type: 'json' }) || { count: 0, resetAt: now + RATE_LIMIT_CONFIG.windowMs };
  
  if (data.resetAt < now) {
    data.count = 0;
    data.resetAt = now + RATE_LIMIT_CONFIG.windowMs;
  }
  
  if (data.count >= RATE_LIMIT_CONFIG.maxRequests) {
    return { allowed: false, resetAt: data.resetAt };
  }
  
  data.count++;
  await KV.put(key, JSON.stringify(data), { expirationTtl: RATE_LIMIT_CONFIG.windowMs / 1000 });
  
  return { allowed: true, remaining: RATE_LIMIT_CONFIG.maxRequests - data.count };
}

请求头部处理

安全头部设置

设置安全相关的 HTTP 响应头部。

// 设置安全头部
function setSecurityHeaders(response) {
  // 防止点击劫持
  response.headers.set('X-Frame-Options', 'DENY');
  
  // 防止 MIME 类型嗅探
  response.headers.set('X-Content-Type-Options', 'nosniff');
  
  // 启用 XSS 保护
  response.headers.set('X-XSS-Protection', '1; mode=block');
  
  // 严格传输安全
  response.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  
  // 内容安全策略
  response.headers.set('Content-Security-Policy', "default-src 'self'");
  
  // 引用策略
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
  
  return response;
}

头部过滤

过滤敏感的请求头部,防止信息泄露。

// 需要过滤的敏感头部
const SENSITIVE_HEADERS = [
  'authorization',
  'cookie',
  'set-cookie',
  'x-api-key',
  'x-auth-token',
  'proxy-authorization'
];

// 过滤头部
function filterHeaders(headers) {
  const filtered = new Headers();
  
  for (const [key, value] of headers.entries()) {
    const lowerKey = key.toLowerCase();
    
    if (!SENSITIVE_HEADERS.includes(lowerKey)) {
      filtered.set(key, value);
    }
  }
  
  return filtered;
}

头部重写

重写请求头部以匹配目标服务器的要求。

// 头部重写规则
const HEADER_REWRITE_RULES = {
  'host': (url) => new URL(url).hostname,
  'origin': (url) => new URL(url).origin,
  'referer': (url) => new URL(url).origin
};

// 重写头部
function rewriteHeaders(headers, targetUrl) {
  const rewritten = new Headers(headers);
  
  for (const [header, rewriter] of Object.entries(HEADER_REWRITE_RULES)) {
    if (rewritten.has(header)) {
      rewritten.set(header, rewriter(targetUrl));
    }
  }
  
  return rewritten;
}

超时保护

请求超时

设置合理的请求超时时间,防止长时间挂起的请求。

// 超时配置
const TIMEOUT_CONFIG = {
  connect: 10000,    // 连接超时:10 秒
  read: 30000,       // 读取超时:30 秒
  write: 30000,      // 写入超时:30 秒
  total: 60000       // 总超时:60 秒
};

// 带超时的请求
async function fetchWithTimeout(url, options = {}) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_CONFIG.total);
  
  try {
    const response = await fetch(url, {
      ...options,
      signal: controller.signal
    });
    
    clearTimeout(timeoutId);
    return response;
  } catch (error) {
    clearTimeout(timeoutId);
    
    if (error.name === 'AbortError') {
      throw new Error('Request timeout');
    }
    
    throw error;
  }
}

连接超时

控制连接建立的超时时间。

// 连接超时控制
async function connectWithTimeout(url, timeout = TIMEOUT_CONFIG.connect) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);
  
  try {
    const response = await fetch(url, {
      method: 'HEAD',
      signal: controller.signal
    });
    
    clearTimeout(timeoutId);
    return response;
  } catch (error) {
    clearTimeout(timeoutId);
    
    if (error.name === 'AbortError') {
      throw new Error('Connection timeout');
    }
    
    throw error;
  }
}

错误处理

错误分类

对不同类型的错误进行分类处理。

// 错误类型
const ERROR_TYPES = {
  NETWORK_ERROR: 'NETWORK_ERROR',
  TIMEOUT_ERROR: 'TIMEOUT_ERROR',
  RATE_LIMIT_ERROR: 'RATE_LIMIT_ERROR',
  VALIDATION_ERROR: 'VALIDATION_ERROR',
  SERVER_ERROR: 'SERVER_ERROR',
  CLIENT_ERROR: 'CLIENT_ERROR'
};

// 错误处理函数
function handleError(error) {
  if (error.name === 'AbortError') {
    return {
      type: ERROR_TYPES.TIMEOUT_ERROR,
      message: 'Request timeout',
      status: 504
    };
  }
  
  if (error.message.includes('fetch failed')) {
    return {
      type: ERROR_TYPES.NETWORK_ERROR,
      message: 'Network error',
      status: 502
    };
  }
  
  if (error.status >= 500) {
    return {
      type: ERROR_TYPES.SERVER_ERROR,
      message: 'Server error',
      status: error.status
    };
  }
  
  if (error.status >= 400) {
    return {
      type: ERROR_TYPES.CLIENT_ERROR,
      message: 'Client error',
      status: error.status
    };
  }
  
  return {
    type: ERROR_TYPES.SERVER_ERROR,
    message: 'Unknown error',
    status: 500
  };
}

错误响应

返回友好的错误响应。

// 错误响应
function errorResponse(error) {
  const errorInfo = handleError(error);
  
  return new Response(JSON.stringify({
    error: errorInfo.message,
    type: errorInfo.type,
    timestamp: new Date().toISOString()
  }), {
    status: errorInfo.status,
    headers: {
      'Content-Type': 'application/json'
    }
  });
}

重试机制

对可重试的错误实现自动重试。

// 重试配置
const RETRY_CONFIG = {
  maxRetries: 3,
  retryDelay: 1000,
  retryableStatuses: [408, 429, 500, 502, 503, 504],
  retryableErrors: ['NETWORK_ERROR', 'TIMEOUT_ERROR']
};

// 带重试的请求
async function fetchWithRetry(url, options = {}, retries = RETRY_CONFIG.maxRetries) {
  try {
    return await fetchWithTimeout(url, options);
  } catch (error) {
    const errorInfo = handleError(error);
    
    if (retries <= 0 || 
        !RETRY_CONFIG.retryableErrors.includes(errorInfo.type)) {
      throw error;
    }
    
    // 指数退避
    const delay = RETRY_CONFIG.retryDelay * Math.pow(2, RETRY_CONFIG.maxRetries - retries);
    await new Promise(resolve => setTimeout(resolve, delay));
    
    return fetchWithRetry(url, options, retries - 1);
  }
}

性能优化

缓存策略

边缘缓存

使用 Cloudflare Cache API 实现边缘缓存。

// 缓存配置
const CACHE_CONFIG = {
  defaultTTL: 1800,        // 默认缓存时间:30 分钟
  maxTTL: 86400,           // 最大缓存时间:24 小时
  staleWhileRevalidate: 60 // 过期后重新验证:1 分钟
};

// 缓存键生成
function generateCacheKey(url) {
  const urlObj = new URL(url);
  return `cache:${urlObj.hostname}:${urlObj.pathname}`;
}

// 获取缓存
async function getFromCache(key) {
  try {
    const cached = await CACHE.get(key, { type: 'arrayBuffer' });
    
    if (cached) {
      return new Response(cached, {
        headers: {
          'X-Cache': 'HIT',
          'X-Cache-Key': key
        }
      });
    }
  } catch (error) {
    console.error('Cache get error:', error);
  }
  
  return null;
}

// 设置缓存
async function setCache(key, response) {
  try {
    const clonedResponse = response.clone();
    const buffer = await clonedResponse.arrayBuffer();
    
    // 根据 Content-Type 设置缓存时间
    const contentType = response.headers.get('Content-Type') || '';
    let ttl = CACHE_CONFIG.defaultTTL;
    
    if (contentType.includes('image/') || contentType.includes('video/')) {
      ttl = CACHE_CONFIG.maxTTL;
    } else if (contentType.includes('text/html') || contentType.includes('application/json')) {
      ttl = CACHE_CONFIG.defaultTTL / 2;
    }
    
    await CACHE.put(key, buffer, {
      expirationTtl: ttl
    });
  } catch (error) {
    console.error('Cache set error:', error);
  }
}

缓存控制

根据不同的资源类型设置不同的缓存策略。

// 缓存策略
const CACHE_STRATEGIES = {
  // 静态资源:长时间缓存
  static: {
    maxAge: 86400,
    staleWhileRevalidate: 3600
  },
  
  // API 响应:短时间缓存
  api: {
    maxAge: 300,
    staleWhileRevalidate: 60
  },
  
  // 动态内容:不缓存
  dynamic: {
    noCache: true
  }
};

// 应用缓存策略
function applyCacheStrategy(response, strategy) {
  const config = CACHE_STRATEGIES[strategy] || CACHE_STRATEGIES.api;
  
  if (config.noCache) {
    response.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate');
  } else {
    response.headers.set('Cache-Control', 
      `public, max-age=${config.maxAge}, stale-while-revalidate=${config.staleWhileRevalidate}`);
  }
  
  return response;
}

缓存失效

实现缓存失效机制。

// 缓存失效
async function invalidateCache(pattern) {
  try {
    // 列出所有缓存键
    const keys = await CACHE.list();
    
    // 过滤匹配的键
    const keysToDelete = keys.keys.filter(key => 
      key.name.includes(pattern)
    );
    
    // 删除匹配的缓存
    await Promise.all(
      keysToDelete.map(key => CACHE.delete(key.name))
    );
    
    return { deleted: keysToDelete.length };
  } catch (error) {
    console.error('Cache invalidate error:', error);
    return { deleted: 0 };
  }
}

// 使用示例
// invalidateCache('github.com'); // 失效所有 GitHub 相关的缓存

压缩优化

响应压缩

对响应内容进行压缩,减少传输数据量。

// 压缩配置
const COMPRESSION_CONFIG = {
  enabled: true,
  minSize: 1024,        // 最小压缩大小:1KB
  level: 6,             // 压缩级别:0-9
  types: [
    'text/plain',
    'text/html',
    'text/css',
    'text/javascript',
    'application/json',
    'application/javascript',
    'application/xml',
    'text/xml'
  ]
};

// 压缩响应
async function compressResponse(response) {
  if (!COMPRESSION_CONFIG.enabled) {
    return response;
  }
  
  const contentType = response.headers.get('Content-Type') || '';
  const contentLength = parseInt(response.headers.get('Content-Length') || '0');
  
  // 检查是否应该压缩
  if (contentLength < COMPRESSION_CONFIG.minSize) {
    return response;
  }
  
  const shouldCompress = COMPRESSION_CONFIG.types.some(type => 
    contentType.includes(type)
  );
  
  if (!shouldCompress) {
    return response;
  }
  
  // 检查客户端是否支持压缩
  const acceptEncoding = response.headers.get('Accept-Encoding') || '';
  
  if (acceptEncoding.includes('br')) {
    return compressWithBrotli(response);
  } else if (acceptEncoding.includes('gzip')) {
    return compressWithGzip(response);
  }
  
  return response;
}

// Brotli 压缩
async function compressWithBrotli(response) {
  const original = await response.arrayBuffer();
  const compressed = await compress(original, { level: COMPRESSION_CONFIG.level });
  
  return new Response(compressed, {
    status: response.status,
    headers: {
      ...response.headers,
      'Content-Encoding': 'br',
      'Content-Length': compressed.length.toString()
    }
  });
}

// Gzip 压缩
async function compressWithGzip(response) {
  const original = await response.arrayBuffer();
  const compressed = await gzip(original, { level: COMPRESSION_CONFIG.level });
  
  return new Response(compressed, {
    status: response.status,
    headers: {
      ...response.headers,
      'Content-Encoding': 'gzip',
      'Content-Length': compressed.length.toString()
    }
  });
}

请求压缩

对请求内容进行压缩。

// 压缩请求
async function compressRequest(body, encoding) {
  if (!body) {
    return body;
  }
  
  if (encoding === 'br') {
    return await compress(body, { level: COMPRESSION_CONFIG.level });
  } else if (encoding === 'gzip') {
    return await gzip(body, { level: COMPRESSION_CONFIG.level });
  }
  
  return body;
}

连接管理

连接池

使用连接池复用连接。

// 连接池配置
const CONNECTION_POOL_CONFIG = {
  maxConnections: 100,    // 最大连接数
  maxIdleConnections: 10, // 最大空闲连接数
  idleTimeout: 60000      // 空闲超时:60 秒
};

// 连接池实现
class ConnectionPool {
  constructor(config) {
    this.config = config;
    this.connections = new Map();
    this.idleConnections = new Map();
  }
  
  async getConnection(url) {
    const key = `${new URL(url).origin}`;
    
    // 检查空闲连接
    if (this.idleConnections.has(key)) {
      const connection = this.idleConnections.get(key);
      this.idleConnections.delete(key);
      return connection;
    }
    
    // 创建新连接
    const connection = await this.createConnection(url);
    this.connections.set(key, connection);
    
    return connection;
  }
  
  async createConnection(url) {
    // 实现连接创建逻辑
    return fetch(url);
  }
  
  releaseConnection(url, connection) {
    const key = `${new URL(url).origin}`;
    
    // 检查空闲连接数量
    if (this.idleConnections.size >= this.config.maxIdleConnections) {
      this.connections.delete(key);
      return;
    }
    
    // 放入空闲连接池
    this.idleConnections.set(key, connection);
    
    // 设置超时清理
    setTimeout(() => {
      this.idleConnections.delete(key);
      this.connections.delete(key);
    }, this.config.idleTimeout);
  }
}

连接复用

复用 HTTP/2 连接。

// HTTP/2 连接复用
const HTTP2_POOL = new Map();

async function fetchWithConnectionReuse(url, options = {}) {
  const origin = new URL(url).origin;
  
  // 获取或创建连接
  if (!HTTP2_POOL.has(origin)) {
    HTTP2_POOL.set(origin, new ConnectionPool(CONNECTION_POOL_CONFIG));
  }
  
  const pool = HTTP2_POOL.get(origin);
  const connection = await pool.getConnection(url);
  
  try {
    return await connection.fetch(url, options);
  } finally {
    pool.releaseConnection(url, connection);
  }
}

内容优化

内容转换

根据客户端能力转换内容格式。

// 内容转换
async function transformContent(response, request) {
  const acceptHeader = request.headers.get('Accept') || '';
  const contentType = response.headers.get('Content-Type') || '';
  
  // JSON 到 XML 转换
  if (acceptHeader.includes('application/xml') && contentType.includes('application/json')) {
    return await jsonToXml(response);
  }
  
  // JSON 到 YAML 转换
  if (acceptHeader.includes('application/x-yaml') && contentType.includes('application/json')) {
    return await jsonToYaml(response);
  }
  
  return response;
}

// JSON 到 XML 转换
async function jsonToXml(response) {
  const json = await response.json();
  const xml = convertJsonToXml(json);
  
  return new Response(xml, {
    status: response.status,
    headers: {
      'Content-Type': 'application/xml'
    }
  });
}

// JSON 到 YAML 转换
async function jsonToYaml(response) {
  const json = await response.json();
  const yaml = convertJsonToYaml(json);
  
  return new Response(yaml, {
    status: response.status,
    headers: {
      'Content-Type': 'application/x-yaml'
    }
  });
}

内容适配

根据设备类型适配内容。

// 内容适配
async function adaptContent(response, request) {
  const userAgent = request.headers.get('User-Agent') || '';
  
  // 移动设备适配
  if (isMobileDevice(userAgent)) {
    return await adaptForMobile(response);
  }
  
  // 桌面设备适配
  if (isDesktopDevice(userAgent)) {
    return await adaptForDesktop(response);
  }
  
  return response;
}

// 移动设备适配
async function adaptForMobile(response) {
  const contentType = response.headers.get('Content-Type') || '';
  
  if (contentType.includes('text/html')) {
    const html = await response.text();
    const adapted = optimizeForMobile(html);
    
    return new Response(adapted, {
      status: response.status,
      headers: response.headers
    });
  }
  
  return response;
}

// 桌面设备适配
async function adaptForDesktop(response) {
  const contentType = response.headers.get('Content-Type') || '';
  
  if (contentType.includes('text/html')) {
    const html = await response.text();
    const adapted = optimizeForDesktop(html);
    
    return new Response(adapted, {
      status: response.status,
      headers: response.headers
    });
  }
  
  return response;
}

监控和日志

请求监控

性能指标

收集和记录性能指标。

// 性能指标收集
const performanceMetrics = {
  requestCount: 0,
  successCount: 0,
  errorCount: 0,
  totalLatency: 0,
  cacheHitCount: 0,
  cacheMissCount: 0
};

// 记录请求指标
function recordRequestMetrics(startTime, cacheHit, success) {
  const latency = Date.now() - startTime;
  
  performanceMetrics.requestCount++;
  performanceMetrics.totalLatency += latency;
  
  if (cacheHit) {
    performanceMetrics.cacheHitCount++;
  } else {
    performanceMetrics.cacheMissCount++;
  }
  
  if (success) {
    performanceMetrics.successCount++;
  } else {
    performanceMetrics.errorCount++;
  }
}

// 获取性能指标
function getPerformanceMetrics() {
  const avgLatency = performanceMetrics.totalLatency / performanceMetrics.requestCount;
  const cacheHitRate = performanceMetrics.cacheHitCount / 
    (performanceMetrics.cacheHitCount + performanceMetrics.cacheMissCount);
  const errorRate = performanceMetrics.errorCount / performanceMetrics.requestCount;
  
  return {
    requestCount: performanceMetrics.requestCount,
    successCount: performanceMetrics.successCount,
    errorCount: performanceMetrics.errorCount,
    avgLatency: avgLatency,
    cacheHitRate: cacheHitRate,
    errorRate: errorRate
  };
}

实时监控

实现实时监控功能。

// 实时监控
async function monitorRequest(request, response) {
  const startTime = Date.now();
  
  // 记录请求信息
  const requestInfo = {
    method: request.method,
    url: request.url,
    headers: Object.fromEntries(request.headers.entries()),
    timestamp: new Date().toISOString()
  };
  
  // 记录响应信息
  const responseInfo = {
    status: response.status,
    headers: Object.fromEntries(response.headers.entries()),
    latency: Date.now() - startTime,
    timestamp: new Date().toISOString()
  };
  
  // 发送到监控系统
  await sendToMonitoringSystem({
    request: requestInfo,
    response: responseInfo
  });
}

// 发送到监控系统
async function sendToMonitoringSystem(data) {
  // 实现发送逻辑,例如发送到 Cloudflare Analytics 或自定义监控服务
  console.log('Monitoring data:', JSON.stringify(data));
}

日志记录

结构化日志

使用结构化日志格式。

// 日志级别
const LOG_LEVELS = {
  DEBUG: 'DEBUG',
  INFO: 'INFO',
  WARN: 'WARN',
  ERROR: 'ERROR'
};

// 结构化日志
function log(level, message, context = {}) {
  const logEntry = {
    timestamp: new Date().toISOString(),
    level: level,
    message: message,
    context: context
  };
  
  console.log(JSON.stringify(logEntry));
}

// 使用示例
log(LOG_LEVELS.INFO, 'Request received', {
  method: 'GET',
  url: 'https://example.com',
  ip: '192.168.1.1'
});

错误日志

记录详细的错误信息。

// 错误日志
function logError(error, context = {}) {
  log(LOG_LEVELS.ERROR, error.message, {
    stack: error.stack,
    ...context
  });
}

// 使用示例
try {
  await fetch(url);
} catch (error) {
  logError(error, {
    url: url,
    method: 'GET'
  });
}

最佳实践

安全最佳实践

  1. 最小权限原则

    • 只授予必要的权限
    • 使用最小权限的 API 密钥
  2. 定期更新

    • 定期更新依赖项
    • 及时应用安全补丁
  3. 输入验证

    • 验证所有输入数据
    • 防止注入攻击
  4. 加密传输

    • 使用 HTTPS 加密传输
    • 验证 SSL 证书

性能最佳实践

  1. 缓存优先

    • 优先使用缓存
    • 合理设置缓存时间
  2. 压缩内容

    • 压缩大文件
    • 选择合适的压缩算法
  3. 连接复用

    • 复用 HTTP/2 连接
    • 使用连接池
  4. 异步处理

    • 使用异步操作
    • 避免阻塞请求

监控最佳实践

  1. 关键指标

    • 监控关键性能指标
    • 设置合理的告警阈值
  2. 日志分析

    • 定期分析日志
    • 识别性能瓶颈
  3. 持续优化

    • 持续优化性能
    • 定期审查代码

总结

Xget 通过多层安全机制和全面的性能优化策略,确保了服务的安全性、稳定性和高性能。通过合理的安全防护、缓存策略、压缩优化和连接管理,Xget 能够为用户提供快速、可靠的加速服务。

同时,完善的监控和日志系统帮助及时发现和解决问题,确保服务的持续稳定运行。