/** * 环境端口策略配置 * 类似租户识别系统的环境优先级策略 */ import type { PortStrategy } from './port-manager'; // 环境类型 export type Environment = 'development' | 'test' | 'staging' | 'production'; // 端口策略优先级 export interface PortPriority { environment: Environment; priority: number; // 数字越小优先级越高 description: string; } // 环境端口策略配置 export interface EnvironmentPortStrategy extends PortStrategy { environment: Environment; priority: number; autoDetect: boolean; fallbackStrategy?: EnvironmentPortStrategy; restrictions: { allowedHosts: string[]; blockedPorts: number[]; requireHttps: boolean; }; } // 端口分配模式 export enum PortAllocationMode { TENANT_BASED = 'tenant-based', // 基于租户分配 SEQUENTIAL = 'sequential', // 顺序分配 RANDOM = 'random', // 随机分配 HASH_BASED = 'hash-based' // 基于哈希分配 } // 环境检测器 export class EnvironmentDetector { /** * 检测当前环境 */ static detectEnvironment(): Environment { // 1. 检查环境变量 const nodeEnv = process.env.NODE_ENV; if (nodeEnv) { switch (nodeEnv.toLowerCase()) { case 'development': case 'dev': return 'development'; case 'test': case 'testing': return 'test'; case 'staging': case 'stage': return 'staging'; case 'production': case 'prod': return 'production'; } } // 2. 检查域名 const hostname = window.location.hostname; if (hostname.includes('localhost') || hostname.includes('127.0.0.1')) { return 'development'; } if (hostname.includes('test') || hostname.includes('staging')) { return 'test'; } if (hostname.includes('prod') || hostname.includes('www')) { return 'production'; } // 3. 检查端口 const port = window.location.port; if (port && parseInt(port) < 4000) { return 'development'; } // 默认返回开发环境 return 'development'; } /** * 获取环境建议 */ static getEnvironmentRecommendation(): { detected: Environment; confidence: number; reasons: string[]; suggestions: string[]; } { const reasons: string[] = []; const suggestions: string[] = []; let confidence = 0; const nodeEnv = process.env.NODE_ENV; const hostname = window.location.hostname; const port = window.location.port; const protocol = window.location.protocol; // 分析环境变量 if (nodeEnv) { reasons.push(`NODE_ENV: ${nodeEnv}`); confidence += 40; } else { suggestions.push('建议设置 NODE_ENV 环境变量'); } // 分析域名 if (hostname.includes('localhost')) { reasons.push('域名包含 localhost'); confidence += 30; } else if (hostname.includes('test')) { reasons.push('域名包含 test'); confidence += 25; } else if (hostname.includes('prod')) { reasons.push('域名包含 prod'); confidence += 35; } // 分析协议 if (protocol === 'https:') { reasons.push('使用 HTTPS 协议'); confidence += 10; } else { suggestions.push('生产环境建议使用 HTTPS'); } // 分析端口 if (port) { const portNum = parseInt(port); if (portNum >= 3000 && portNum < 4000) { reasons.push('使用开发端口范围'); confidence += 15; } } return { detected: this.detectEnvironment(), confidence: Math.min(confidence, 100), reasons, suggestions }; } } // 端口策略管理器 export class PortStrategyManager { private strategies: Map; private currentEnvironment: Environment; constructor() { this.currentEnvironment = EnvironmentDetector.detectEnvironment(); this.strategies = new Map(); this.initializeDefaultStrategies(); } /** * 初始化默认策略 */ private initializeDefaultStrategies(): void { // 开发环境策略 this.strategies.set('development', { environment: 'development', priority: 1, basePort: 3000, portRange: [3000, 3999], tenantOffset: 10, environmentOffset: 0, maxRetries: 50, autoDetect: true, restrictions: { allowedHosts: ['localhost', '127.0.0.1', '0.0.0.0'], blockedPorts: [], requireHttps: false } }); // 测试环境策略 this.strategies.set('test', { environment: 'test', priority: 2, basePort: 4000, portRange: [4000, 4999], tenantOffset: 5, environmentOffset: 1000, maxRetries: 30, autoDetect: true, restrictions: { allowedHosts: ['localhost', '127.0.0.1', 'test.local'], blockedPorts: [4444, 4567], // 避免与其他测试工具冲突 requireHttps: false } }); // 预发布环境策略 this.strategies.set('staging', { environment: 'staging', priority: 3, basePort: 5000, portRange: [5000, 5999], tenantOffset: 3, environmentOffset: 2000, maxRetries: 20, autoDetect: true, restrictions: { allowedHosts: ['staging.local', 'stage.example.com'], blockedPorts: [], requireHttps: true } }); // 生产环境策略 this.strategies.set('production', { environment: 'production', priority: 4, basePort: 8080, portRange: [8080, 8999], tenantOffset: 1, environmentOffset: 5000, maxRetries: 10, autoDetect: false, // 生产环境不自动检测 restrictions: { allowedHosts: ['0.0.0.0'], // 生产环境通常绑定所有接口 blockedPorts: [8080, 8443], // 避免与常用服务冲突 requireHttps: true } }); } /** * 获取当前环境策略 */ getCurrentStrategy(): EnvironmentPortStrategy { const strategy = this.strategies.get(this.currentEnvironment); if (!strategy) { console.warn(`未找到环境 ${this.currentEnvironment} 的策略,使用开发环境策略`); return this.strategies.get('development')!; } return strategy; } /** * 获取指定环境策略 */ getStrategy(environment: Environment): EnvironmentPortStrategy | undefined { return this.strategies.get(environment); } /** * 设置环境策略 */ setStrategy(environment: Environment, strategy: EnvironmentPortStrategy): void { this.strategies.set(environment, strategy); console.log(`✅ 已更新 ${environment} 环境的端口策略`); } /** * 获取推荐策略(基于环境优先级) */ getRecommendedStrategy(): { primary: EnvironmentPortStrategy; fallback: EnvironmentPortStrategy[]; reasoning: string[]; } { const current = this.getCurrentStrategy(); const reasoning: string[] = []; const fallback: EnvironmentPortStrategy[] = []; reasoning.push(`当前环境: ${this.currentEnvironment}`); reasoning.push(`优先级: ${current.priority}`); // 获取备选策略(按优先级排序) const allStrategies = Array.from(this.strategies.values()) .filter(s => s.environment !== this.currentEnvironment) .sort((a, b) => a.priority - b.priority); fallback.push(...allStrategies); // 环境特定的推理 switch (this.currentEnvironment) { case 'development': reasoning.push('开发环境优先考虑端口可用性和调试便利性'); break; case 'test': reasoning.push('测试环境需要隔离性和可重复性'); break; case 'staging': reasoning.push('预发布环境模拟生产环境配置'); break; case 'production': reasoning.push('生产环境优先考虑安全性和稳定性'); break; } return { primary: current, fallback, reasoning }; } /** * 验证端口策略 */ validateStrategy(strategy: EnvironmentPortStrategy): { isValid: boolean; errors: string[]; warnings: string[]; } { const errors: string[] = []; const warnings: string[] = []; // 检查端口范围 if (strategy.portRange[0] >= strategy.portRange[1]) { errors.push('端口范围无效:起始端口必须小于结束端口'); } if (strategy.portRange[0] < 1024 && strategy.environment === 'production') { warnings.push('生产环境使用系统端口(<1024)可能需要管理员权限'); } // 检查基础端口 if (strategy.basePort < strategy.portRange[0] || strategy.basePort > strategy.portRange[1]) { errors.push('基础端口不在允许的端口范围内'); } // 检查租户偏移 if (strategy.tenantOffset <= 0) { warnings.push('租户偏移为0可能导致端口冲突'); } // 检查环境特定规则 if (strategy.environment === 'production' && !strategy.restrictions.requireHttps) { warnings.push('生产环境建议启用 HTTPS'); } if (strategy.environment === 'development' && strategy.restrictions.requireHttps) { warnings.push('开发环境启用 HTTPS 可能增加配置复杂度'); } return { isValid: errors.length === 0, errors, warnings }; } /** * 获取环境统计信息 */ getEnvironmentStats(): { current: Environment; available: Environment[]; strategies: Array<{ environment: Environment; priority: number; portRange: [number, number]; isValid: boolean; }>; } { const strategies = Array.from(this.strategies.entries()).map(([env, strategy]) => ({ environment: env, priority: strategy.priority, portRange: strategy.portRange, isValid: this.validateStrategy(strategy).isValid })); return { current: this.currentEnvironment, available: Array.from(this.strategies.keys()), strategies: strategies.sort((a, b) => a.priority - b.priority) }; } /** * 切换环境 */ switchEnvironment(environment: Environment): boolean { if (!this.strategies.has(environment)) { console.error(`环境 ${environment} 不存在`); return false; } this.currentEnvironment = environment; console.log(`🔄 已切换到 ${environment} 环境`); return true; } } // 导出默认实例 export const portStrategyManager = new PortStrategyManager(); // 导出环境优先级配置 export const ENVIRONMENT_PRIORITIES: PortPriority[] = [ { environment: 'development', priority: 1, description: '开发环境 - 最高优先级,注重便利性' }, { environment: 'test', priority: 2, description: '测试环境 - 高优先级,注重隔离性' }, { environment: 'staging', priority: 3, description: '预发布环境 - 中等优先级,模拟生产' }, { environment: 'production', priority: 4, description: '生产环境 - 最低优先级,注重安全性' } ];