feat: 增强错误处理逻辑,添加 Cloudflare 风控和网络超时拦截提示

This commit is contained in:
QLHazyCoder
2026-04-18 20:54:00 +08:00
parent 82471af931
commit 609cdeaeb5
12 changed files with 440 additions and 17 deletions
+101
View File
@@ -132,6 +132,10 @@ const CLOUDFLARE_TEMP_EMAIL_PROVIDER = 'cloudflare-temp-email';
const CLOUDFLARE_TEMP_EMAIL_GENERATOR = 'cloudflare-temp-email';
const HOTMAIL_MAILBOXES = ['INBOX', 'Junk'];
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
const CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX = 'CF_SECURITY_BLOCKED::';
const CLOUDFLARE_SECURITY_BLOCK_USER_MESSAGE = '您已触发Cloudflare 安全防护系统,已完全停止流程,请不要短时间内多次进行重新发送验证码,连续刷新、反复点击重试会加重风控;请先关闭页面等待 15-30 分钟,让系统的临时限制自动解除。或者更换浏览器';
const NETWORK_TIMEOUT_BLOCK_ERROR_PREFIX = 'NETWORK_TIMEOUT_BLOCKED::';
const NETWORK_TIMEOUT_BLOCK_USER_MESSAGE = '请检查当前网络节点是否稳定,若你使用的代理 / /VPN 节点无延迟过高问题,请换一个服务器继续使用此邮箱继续登陆';
const HUMAN_STEP_DELAY_MIN = 700;
const HUMAN_STEP_DELAY_MAX = 2200;
const STEP6_MAX_ATTEMPTS = 3;
@@ -3836,6 +3840,78 @@ function getErrorMessage(error) {
return String(typeof error === 'string' ? error : error?.message || '');
}
function isCloudflareSecurityBlockedError(error) {
return getErrorMessage(error).startsWith(CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX);
}
function isNetworkTimeoutBlockedError(error) {
return getErrorMessage(error).startsWith(NETWORK_TIMEOUT_BLOCK_ERROR_PREFIX);
}
function isTerminalSecurityBlockedError(error) {
return isCloudflareSecurityBlockedError(error) || isNetworkTimeoutBlockedError(error);
}
function getCloudflareSecurityBlockedMessage(error) {
const message = getErrorMessage(error);
if (message.startsWith(CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX)) {
return message.slice(CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX.length).trim() || CLOUDFLARE_SECURITY_BLOCK_USER_MESSAGE;
}
return CLOUDFLARE_SECURITY_BLOCK_USER_MESSAGE;
}
function getNetworkTimeoutBlockedMessage(error) {
const message = getErrorMessage(error);
if (message.startsWith(NETWORK_TIMEOUT_BLOCK_ERROR_PREFIX)) {
return message.slice(NETWORK_TIMEOUT_BLOCK_ERROR_PREFIX.length).trim() || NETWORK_TIMEOUT_BLOCK_USER_MESSAGE;
}
return NETWORK_TIMEOUT_BLOCK_USER_MESSAGE;
}
function getTerminalSecurityBlockedMessage(error) {
if (isNetworkTimeoutBlockedError(error)) {
return getNetworkTimeoutBlockedMessage(error);
}
return getCloudflareSecurityBlockedMessage(error);
}
function getTerminalSecurityBlockedAlertText(error) {
if (isNetworkTimeoutBlockedError(error)) {
return '检测到网络节点异常,请暂停当前操作。';
}
return '检测到 Cloudflare 风控,请暂停当前操作。';
}
function getTerminalSecurityBlockedTitle(error) {
if (isNetworkTimeoutBlockedError(error)) {
return '网络节点异常';
}
return 'Cloudflare 风控拦截';
}
function broadcastSecurityBlockedAlert(title = '流程已完全停止', message = CLOUDFLARE_SECURITY_BLOCK_USER_MESSAGE, alertText = '检测到 Cloudflare 风控,请暂停当前操作。') {
chrome.runtime.sendMessage({
type: 'SECURITY_BLOCKED_ALERT',
payload: {
title,
message,
alert: {
text: alertText,
tone: 'danger',
},
},
}).catch(() => { });
}
async function handleCloudflareSecurityBlocked(error) {
const title = getTerminalSecurityBlockedTitle(error);
const message = getTerminalSecurityBlockedMessage(error);
const alertText = getTerminalSecurityBlockedAlertText(error);
await requestStop({ logMessage: message });
broadcastSecurityBlockedAlert(title, message, alertText);
return message;
}
function isVerificationMailPollingError(error) {
if (typeof loggingStatus !== 'undefined' && loggingStatus?.isVerificationMailPollingError) {
return loggingStatus.isVerificationMailPollingError(error);
@@ -4977,6 +5053,10 @@ async function executeStep(step, options = {}) {
await appendManualAccountRunRecordIfNeeded(`step${step}_stopped`, state, getErrorMessage(err));
throw err;
}
if (isTerminalSecurityBlockedError(err)) {
await handleCloudflareSecurityBlocked(err);
throw new Error(STOP_ERROR_MESSAGE);
}
if (!(deferRetryableTransportError && doesStepUseCompletionSignal(step) && isRetryableContentScriptTransportError(err))) {
await setStepStatus(step, 'failed');
await addLog(`步骤 ${step} 失败:${err.message}`, 'error');
@@ -5909,9 +5989,11 @@ const messageRouter = self.MultiPageBackgroundMessageRouter?.createMessageRouter
getSourceLabel,
getState,
getStopRequested: () => stopRequested,
handleCloudflareSecurityBlocked,
handleAutoRunLoopUnhandledError,
importSettingsBundle,
invalidateDownstreamAfterStepRestart,
isCloudflareSecurityBlockedError: isTerminalSecurityBlockedError,
isAutoRunLockedState,
isHotmailProvider,
isLocalhostOAuthCallbackUrl,
@@ -6445,6 +6527,13 @@ async function ensureStep8VerificationPageReady(options = {}) {
return pageState;
}
if (pageState.maxCheckAttemptsBlocked) {
throw new Error(`${CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX}${CLOUDFLARE_SECURITY_BLOCK_USER_MESSAGE}`);
}
if (pageState.operationTimedOutBlocked) {
throw new Error(`${NETWORK_TIMEOUT_BLOCK_ERROR_PREFIX}${NETWORK_TIMEOUT_BLOCK_USER_MESSAGE}`);
}
if (pageState.state === 'login_timeout_error_page') {
const urlPart = pageState.url ? ` URL: ${pageState.url}` : '';
throw new Error(`STEP8_RESTART_STEP7::步骤 8:当前认证页进入登录超时报错页,请回到步骤 7 重新开始。${urlPart}`.trim());
@@ -6593,6 +6682,12 @@ async function waitForStep8Ready(tabId, timeoutMs = STEP8_READY_WAIT_TIMEOUT_MS)
while (Date.now() - start < timeoutMs) {
throwIfStopped();
const pageState = await getStep8PageState(tabId);
if (pageState?.maxCheckAttemptsBlocked) {
throw new Error(`${CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX}${CLOUDFLARE_SECURITY_BLOCK_USER_MESSAGE}`);
}
if (pageState?.operationTimedOutBlocked) {
throw new Error(`${NETWORK_TIMEOUT_BLOCK_ERROR_PREFIX}${NETWORK_TIMEOUT_BLOCK_USER_MESSAGE}`);
}
if (pageState?.addPhonePage) {
throw new Error('步骤 9:认证页进入了手机号页面,当前不是 OAuth 同意页,无法继续自动授权。');
}
@@ -6768,6 +6863,12 @@ async function waitForStep8ClickEffect(tabId, baselineUrl, timeoutMs = STEP8_CLI
}
const pageState = await getStep8PageState(tabId);
if (pageState?.maxCheckAttemptsBlocked) {
throw new Error(`${CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX}${CLOUDFLARE_SECURITY_BLOCK_USER_MESSAGE}`);
}
if (pageState?.operationTimedOutBlocked) {
throw new Error(`${NETWORK_TIMEOUT_BLOCK_ERROR_PREFIX}${NETWORK_TIMEOUT_BLOCK_USER_MESSAGE}`);
}
if (pageState?.addPhonePage) {
throw new Error('步骤 9:点击“继续”后页面跳到了手机号页面,当前流程无法继续自动授权。');
}