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;
}
}