Skip to content

9. 错误恢复与安全

9.1 错误恢复策略

typescript
class RecoveryManager {
  private strategies: Map<string, RecoveryStrategy> = new Map([
    ['page_load_failed', {
      detect: (error) => error.includes('timeout') || error.includes('net::'),
      recover: async (agent) => {
        // 重试导航
        await agent.browser.reload();
        return await agent.wait(3000);
      }
    }],
    
    ['element_not_found', {
      detect: (error) => error.includes('not found') || error.includes('no such element'),
      recover: async (agent) => {
        // 截图分析,尝试替代定位方式
        const screenshot = await agent.browser.screenshot();
        const alternative = await agent.analyzeForAlternative(screenshot);
        if (alternative) {
          await agent.browser.click(alternative);
          return true;
        }
        return false;
      }
    }],
    
    ['captcha_detected', {
      detect: (error, screenshot) => this.detectCaptcha(screenshot),
      recover: async (agent) => {
        // 通知用户处理验证码
        await agent.message({
          type: 'question',
          content: '检测到验证码,请手动完成验证后告诉我继续。'
        });
        return await agent.waitForUserConfirmation(300); // 5分钟超时
      }
    }],
    
    ['login_required', {
      detect: (error, screenshot) => this.detectLoginWall(screenshot),
      recover: async (agent) => {
        // 询问用户凭据或跳过
        await agent.message({
          type: 'question',
          content: '需要登录才能继续。请问是否提供登录信息,或者跳过此步骤?'
        });
        return await agent.waitForUserInput();
      }
    }],
    
    ['popup_blocking', {
      detect: (error, screenshot) => this.detectPopup(screenshot),
      recover: async (agent) => {
        // 尝试关闭弹窗
        const closeButton = await agent.findElement(screenshot, 'close button, X, dismiss');
        if (closeButton) {
          await agent.browser.click(closeButton);
          return true;
        }
        await agent.browser.key('Escape');
        return true;
      }
    }]
  ]);
  
  async attemptRecovery(error: Error, agent: Agent): Promise<boolean> {
    const screenshot = await agent.browser.screenshot();
    
    for (const [name, strategy] of this.strategies) {
      if (strategy.detect(error.message, screenshot)) {
        console.log(`Attempting recovery strategy: ${name}`);
        const success = await strategy.recover(agent);
        if (success) {
          console.log(`Recovery successful: ${name}`);
          return true;
        }
      }
    }
    
    return false;
  }
}

9.2 安全限制

typescript
class SecurityGuard {
  private config = {
    // 禁止访问的域名模式
    blockedDomains: [
      /bank/i, /payment/i, /paypal/i, /stripe/i,
      /admin/i, /internal/i, /localhost/i
    ],
    
    // 禁止的 shell 命令
    blockedCommands: [
      /rm\s+-rf\s+\//,       // rm -rf /
      /sudo\s+/,             // sudo
      /chmod\s+777/,         // chmod 777
      /curl.*\|.*sh/,        // curl | sh
      /wget.*\|.*sh/         // wget | sh
    ],
    
    // 敏感操作需要确认
    sensitivePatterns: [
      /password/i, /credential/i, /secret/i, /token/i,
      /delete/i, /remove/i, /drop/i
    ],
    
    // 资源限制
    limits: {
      maxFileSize: 100 * 1024 * 1024, // 100MB
      maxFiles: 1000,
      maxRequestsPerMinute: 60,
      maxExecutionTime: 3600 // 1 hour
    }
  };
  
  async validateNavigation(url: string): Promise<ValidationResult> {
    try {
      const parsed = new URL(url);
      
      for (const pattern of this.config.blockedDomains) {
        if (pattern.test(parsed.hostname)) {
          return {
            allowed: false,
            reason: `Domain ${parsed.hostname} is blocked for security reasons`
          };
        }
      }
      
      return { allowed: true };
    } catch {
      return { allowed: false, reason: 'Invalid URL' };
    }
  }
  
  async validateCommand(command: string): Promise<ValidationResult> {
    for (const pattern of this.config.blockedCommands) {
      if (pattern.test(command)) {
        return {
          allowed: false,
          reason: 'This command is not allowed for security reasons'
        };
      }
    }
    
    return { allowed: true };
  }
  
  async checkSensitiveOperation(action: string): Promise<boolean> {
    for (const pattern of this.config.sensitivePatterns) {
      if (pattern.test(action)) {
        return true; // 需要用户确认
      }
    }
    return false;
  }
}

前端面试知识库