6ba22b214c
移动壳加载失败兜底层只保留脱敏页面路径 移动壳加载失败详情改为稳定文案不直出系统描述 扩展移动壳配置门禁锁定加载失败脱敏边界 补充宿主壳方案和共享决策中的加载失败边界
119 lines
2.6 KiB
TypeScript
119 lines
2.6 KiB
TypeScript
import { shouldOpenInMobileShellWebView } from './navigation';
|
|
|
|
export type MobileShellLoadFailureInput =
|
|
| {
|
|
type: 'native';
|
|
url: string;
|
|
code?: number | null;
|
|
description?: string | null;
|
|
}
|
|
| {
|
|
type: 'http';
|
|
url: string;
|
|
statusCode?: number | null;
|
|
description?: string | null;
|
|
}
|
|
| {
|
|
type: 'process';
|
|
url: string;
|
|
description?: string | null;
|
|
};
|
|
|
|
export type MobileShellLoadFailure = {
|
|
type: 'native' | 'http' | 'process';
|
|
url: string;
|
|
title: string;
|
|
detail: string;
|
|
retryLabel: string;
|
|
};
|
|
|
|
function sameDocumentUrl(
|
|
left: URL,
|
|
right: string | null | undefined,
|
|
allowedOrigin: string,
|
|
) {
|
|
if (!right) {
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
const current = new URL(right, allowedOrigin);
|
|
return (
|
|
left.origin === current.origin &&
|
|
left.pathname === current.pathname &&
|
|
left.search === current.search
|
|
);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function shouldShowLoadFailure(
|
|
rawUrl: string,
|
|
allowedOrigin: string,
|
|
currentPageUrl?: string | null,
|
|
) {
|
|
if (!shouldOpenInMobileShellWebView(rawUrl, allowedOrigin)) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const url = new URL(rawUrl, allowedOrigin);
|
|
return (
|
|
url.origin === allowedOrigin &&
|
|
url.pathname !== '/favicon.ico' &&
|
|
sameDocumentUrl(url, currentPageUrl, allowedOrigin)
|
|
);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function sanitizeLoadFailureUrl(rawUrl: string, allowedOrigin: string) {
|
|
const url = new URL(rawUrl, allowedOrigin);
|
|
return `${url.origin}${url.pathname}`;
|
|
}
|
|
|
|
export function normalizeMobileShellLoadFailure(
|
|
input: MobileShellLoadFailureInput,
|
|
allowedOrigin: string,
|
|
currentPageUrl?: string | null,
|
|
): MobileShellLoadFailure | null {
|
|
if (!shouldShowLoadFailure(input.url, allowedOrigin, currentPageUrl)) {
|
|
return null;
|
|
}
|
|
|
|
const url = sanitizeLoadFailureUrl(input.url, allowedOrigin);
|
|
if (input.type === 'http') {
|
|
const statusCode =
|
|
Number.isInteger(input.statusCode) && input.statusCode
|
|
? input.statusCode
|
|
: null;
|
|
return {
|
|
type: 'http',
|
|
url,
|
|
title: statusCode ? `加载失败 ${statusCode}` : '加载失败',
|
|
detail: '服务器暂时没有返回可用页面',
|
|
retryLabel: '重试',
|
|
};
|
|
}
|
|
|
|
if (input.type === 'process') {
|
|
return {
|
|
type: 'process',
|
|
url,
|
|
title: '页面已停止',
|
|
detail: '当前页面连续恢复失败',
|
|
retryLabel: '重试',
|
|
};
|
|
}
|
|
|
|
return {
|
|
type: 'native',
|
|
url,
|
|
title: '网络不可用',
|
|
detail: '当前页面没有加载成功',
|
|
retryLabel: '重试',
|
|
};
|
|
}
|