错误代码参考
HTML Layout Parser 使用结构化的错误代码系统,帮助您快速识别和解决问题。
错误代码结构
错误代码采用 4 位数字格式:CXXX
C- 类别代码 (1-5)XXX- 具体错误编号 (001-999)
成功代码
| 代码 | 描述 |
|---|---|
| 0 | 操作成功完成 |
1xxx - 输入验证错误
这类错误表示输入参数或数据格式有问题。
1001 - HTML 内容为空
描述: 传入的 HTML 字符串为空或只包含空白字符。
原因:
- HTML 参数为空字符串
- HTML 参数为 null 或 undefined
- HTML 只包含空格、换行等空白字符
解决方案:
typescript
// ❌ 错误
parser.parse('', { viewportWidth: 800 });
parser.parse(' \n\t ', { viewportWidth: 800 });
// ✅ 正确
parser.parse('<div>Hello</div>', { viewportWidth: 800 });1002 - 视口宽度无效
描述: 视口宽度参数无效。
原因:
- viewportWidth 为 0 或负数
- viewportWidth 为 NaN
- viewportWidth 未提供
解决方案:
typescript
// ❌ 错误
parser.parse(html, { viewportWidth: 0 });
parser.parse(html, { viewportWidth: -100 });
// ✅ 正确
parser.parse(html, { viewportWidth: 800 });
parser.parse(html, { viewportWidth: 1200 });1003 - CSS 语法错误
描述: CSS 字符串包含语法错误。
原因:
- CSS 选择器语法错误
- CSS 属性值格式错误
- CSS 规则不完整
解决方案:
typescript
// ❌ 错误
const badCSS = '.title { color: ; }'; // 缺少值
const badCSS2 = '.title color: red; }'; // 缺少大括号
// ✅ 正确
const goodCSS = '.title { color: red; }';
parser.parse(html, { viewportWidth: 800, css: goodCSS });1004 - 参数类型错误
描述: 传入参数的类型不正确。
原因:
- HTML 参数不是字符串
- 选项参数不是对象
- 数值参数传入了字符串
解决方案:
typescript
// ❌ 错误
parser.parse(123, { viewportWidth: 800 }); // HTML 不是字符串
parser.parse(html, { viewportWidth: '800' }); // 宽度不是数字
// ✅ 正确
parser.parse(html, { viewportWidth: 800 });1005 - 文档大小超过限制
描述: HTML 文档大小超过了设置的限制。
原因:
- HTML 字符串长度超过 maxCharacters 设置
- 文档过于复杂,超过内部处理限制
解决方案:
typescript
// 增加字符限制
parser.parse(html, {
viewportWidth: 800,
maxCharacters: 100000 // 增加到 100,000 字符
});
// 或者分块处理
function parseInChunks(html: string, chunkSize: number = 50000) {
const chunks = [];
for (let i = 0; i < html.length; i += chunkSize) {
const chunk = html.slice(i, i + chunkSize);
chunks.push(parser.parse(chunk, { viewportWidth: 800 }));
}
return chunks;
}2xxx - 字体相关错误
这类错误与字体加载、管理相关。
2001 - 字体数据无效
描述: 字体文件数据格式无效或损坏。
原因:
- 字体文件不是有效的 TTF/OTF 格式
- 字体数据在传输过程中损坏
- 传入的不是字体数据
解决方案:
typescript
// 验证字体数据
async function loadFontSafely(fontUrl: string, fontName: string) {
try {
const response = await fetch(fontUrl);
if (!response.ok) {
throw new Error(`字体下载失败: ${response.status}`);
}
const fontData = new Uint8Array(await response.arrayBuffer());
// 检查字体文件头
if (fontData.length < 4) {
throw new Error('字体文件太小');
}
const fontId = parser.loadFont(fontData, fontName);
if (fontId <= 0) {
throw new Error('字体加载失败');
}
return fontId;
} catch (error) {
console.error('字体加载错误:', error);
return null;
}
}2002 - 字体加载失败
描述: 字体加载过程中发生错误。
原因:
- 内存不足
- 字体格式不支持
- 系统资源限制
解决方案:
typescript
// 重试机制
async function loadFontWithRetry(fontData: Uint8Array, fontName: string, maxRetries: number = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const fontId = parser.loadFont(fontData, fontName);
if (fontId > 0) {
return fontId;
}
} catch (error) {
console.warn(`字体加载尝试 ${i + 1} 失败:`, error);
if (i < maxRetries - 1) {
// 清理内存后重试
parser.clearCache();
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
throw new Error(`字体加载失败,已重试 ${maxRetries} 次`);
}2003 - 字体 ID 不存在
描述: 尝试使用不存在的字体 ID。
原因:
- 字体已被卸载
- 使用了错误的字体 ID
- 字体加载失败但仍尝试使用
解决方案:
typescript
// 验证字体 ID
function validateFontId(fontId: number): boolean {
const loadedFonts = parser.getLoadedFonts();
return loadedFonts.some(font => font.id === fontId);
}
// 安全使用字体
function parseWithFont(html: string, fontId: number) {
if (!validateFontId(fontId)) {
console.warn(`字体 ID ${fontId} 不存在,使用默认字体`);
return parser.parse(html, { viewportWidth: 800 });
}
return parser.parse(html, {
viewportWidth: 800,
defaultFontId: fontId
});
}2004 - 字体格式不支持
描述: 字体文件格式不被支持。
支持的格式:
- TTF (TrueType Font)
- OTF (OpenType Font)
不支持的格式:
- WOFF/WOFF2(后续版本计划支持)
- EOT
- SVG 字体
解决方案:
typescript
// 检查字体格式
function checkFontFormat(fontData: Uint8Array): string {
if (fontData.length < 4) return 'unknown';
const header = Array.from(fontData.slice(0, 4))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
switch (header) {
case '00010000':
case '74727565': // 'true'
return 'ttf';
case '4f54544f': // 'OTTO'
return 'otf';
case '774f4646': // 'wOFF'
return 'woff';
case '774f4632': // 'wOF2'
return 'woff2';
default:
return 'unknown';
}
}
// 使用示例
const format = checkFontFormat(fontData);
if (format !== 'ttf' && format !== 'otf') {
console.error(`不支持的字体格式: ${format}`);
// 目前需要转换为 TTF/OTF 格式,或等待后续版本支持
}2005 - 默认字体未设置
描述: 尝试解析但没有设置默认字体。
解决方案:
typescript
// 确保设置默认字体
async function ensureDefaultFont() {
const loadedFonts = parser.getLoadedFonts();
if (loadedFonts.length === 0) {
// 加载默认字体
const response = await fetch('/fonts/arial.ttf');
const fontData = new Uint8Array(await response.arrayBuffer());
const fontId = parser.loadFont(fontData, 'Arial');
if (fontId > 0) {
parser.setDefaultFont(fontId);
} else {
throw new Error('无法加载默认字体');
}
} else {
// 使用第一个已加载的字体作为默认字体
parser.setDefaultFont(loadedFonts[0].id);
}
}
// 解析前检查
await ensureDefaultFont();
const layouts = parser.parse(html, { viewportWidth: 800 });3xxx - 解析错误
这类错误发生在 HTML/CSS 解析过程中。
3001 - HTML 解析失败
描述: HTML 文档解析过程中发生错误。
原因:
- HTML 结构严重错误
- 包含不支持的标签或属性
- 文档编码问题
解决方案:
typescript
// 简化 HTML 结构
function simplifyHTML(html: string): string {
return html
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '') // 移除 script
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '') // 移除 style
.replace(/<!--[\s\S]*?-->/g, '') // 移除注释
.replace(/\s+/g, ' ') // 合并空白
.trim();
}
// 尝试解析简化版本
try {
const layouts = parser.parse(html, { viewportWidth: 800 });
} catch (error) {
console.warn('原始 HTML 解析失败,尝试简化版本');
const simplifiedHTML = simplifyHTML(html);
const layouts = parser.parse(simplifiedHTML, { viewportWidth: 800 });
}3002 - CSS 解析失败
描述: CSS 样式解析过程中发生错误。
原因:
- CSS 语法错误
- 使用了不支持的 CSS 属性
- CSS 规则过于复杂
解决方案:
typescript
// CSS 清理函数
function sanitizeCSS(css: string): string {
return css
.replace(/@import[^;]+;/g, '') // 移除 @import
.replace(/@media[^{]+\{[^}]*\}/g, '') // 移除 @media
.replace(/\/\*[\s\S]*?\*\//g, '') // 移除注释
.replace(/\s+/g, ' ') // 合并空白
.trim();
}
// 使用清理后的 CSS
const cleanCSS = sanitizeCSS(originalCSS);
const layouts = parser.parse(html, {
viewportWidth: 800,
css: cleanCSS
});3003 - 布局计算失败
描述: 布局计算过程中发生错误。
原因:
- 循环依赖的布局规则
- 数值溢出
- 复杂的嵌套结构
解决方案:
typescript
// 限制嵌套深度
function limitNestingDepth(html: string, maxDepth: number = 10): string {
// 简化实现:移除过深的嵌套
let depth = 0;
let result = '';
let inTag = false;
for (let i = 0; i < html.length; i++) {
const char = html[i];
if (char === '<') {
inTag = true;
if (html[i + 1] === '/') {
depth--;
} else {
depth++;
}
if (depth <= maxDepth) {
result += char;
}
} else if (char === '>') {
inTag = false;
if (depth <= maxDepth) {
result += char;
}
} else if (!inTag && depth <= maxDepth) {
result += char;
}
}
return result;
}3004 - 解析超时
描述: 解析过程超过了设置的时间限制。
解决方案:
typescript
// 增加超时时间
const layouts = parser.parse(html, {
viewportWidth: 800,
timeout: 30000 // 30 秒
});
// 或者分块处理
async function parseWithTimeout(html: string, timeoutMs: number = 10000) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error('解析超时'));
}, timeoutMs);
try {
const result = parser.parse(html, { viewportWidth: 800 });
clearTimeout(timer);
resolve(result);
} catch (error) {
clearTimeout(timer);
reject(error);
}
});
}3005 - 不支持的 CSS 属性
描述: CSS 中包含不支持的属性。
支持的主要属性:
- 字体:font-family, font-size, font-weight, font-style
- 颜色:color, background-color
- 文本:text-decoration, letter-spacing
- 布局:display, position, width, height, margin, padding
解决方案:
typescript
// 过滤不支持的 CSS 属性
function filterSupportedCSS(css: string): string {
const supportedProperties = [
'font-family', 'font-size', 'font-weight', 'font-style',
'color', 'background-color', 'opacity',
'text-decoration', 'letter-spacing', 'word-spacing',
'display', 'position', 'width', 'height',
'margin', 'padding', 'border'
];
return css.replace(/([a-z-]+)\s*:\s*[^;]+;/g, (match, property) => {
return supportedProperties.includes(property) ? match : '';
});
}4xxx - 内存错误
这类错误与内存分配和管理相关。
4001 - 内存分配失败
描述: 无法分配所需的内存。
解决方案:
typescript
// 内存清理
function cleanupMemory() {
parser.clearCache();
parser.clearAllFonts();
// 强制垃圾回收(如果可用)
if (global.gc) {
global.gc();
}
}
// 在内存不足时清理
try {
const layouts = parser.parse(html, { viewportWidth: 800 });
} catch (error) {
if (error.message.includes('memory') || error.message.includes('allocation')) {
console.warn('内存不足,清理后重试');
cleanupMemory();
// 重试一次
const layouts = parser.parse(html, { viewportWidth: 800 });
}
}4002 - 内存使用超过限制
描述: 内存使用量超过了 50MB 的安全阈值。
解决方案:
typescript
// 内存监控
function monitorMemory() {
const metrics = parser.getMemoryMetrics();
if (metrics) {
const memoryMB = metrics.totalMemoryUsage / 1024 / 1024;
if (memoryMB > 40) { // 40MB 警告阈值
console.warn(`内存使用较高: ${memoryMB.toFixed(2)} MB`);
// 清理不必要的字体
const fonts = parser.getLoadedFonts();
if (fonts.length > 3) {
// 只保留前 3 个字体
for (let i = 3; i < fonts.length; i++) {
parser.unloadFont(fonts[i].id);
}
}
// 清理缓存
parser.clearCache();
}
}
}
// 定期检查
setInterval(monitorMemory, 10000); // 每 10 秒检查一次4003 - 缓冲区溢出
描述: 内部缓冲区溢出。
解决方案:
typescript
// 限制文档大小
const MAX_HTML_SIZE = 100000; // 100KB
function parseWithSizeLimit(html: string) {
if (html.length > MAX_HTML_SIZE) {
console.warn(`HTML 过大 (${html.length} 字符),截断处理`);
html = html.substring(0, MAX_HTML_SIZE);
}
return parser.parse(html, {
viewportWidth: 800,
maxCharacters: MAX_HTML_SIZE
});
}4004 - 内存泄漏检测到
描述: 检测到可能的内存泄漏。
解决方案:
typescript
// 内存泄漏检测
class MemoryLeakDetector {
private baselineMemory: number = 0;
private checkCount: number = 0;
startMonitoring() {
this.baselineMemory = parser.getTotalMemoryUsage();
this.checkCount = 0;
}
checkForLeaks(): boolean {
this.checkCount++;
const currentMemory = parser.getTotalMemoryUsage();
const growth = currentMemory - this.baselineMemory;
// 如果内存增长超过 10MB 且检查次数超过 10 次
if (growth > 10 * 1024 * 1024 && this.checkCount > 10) {
console.error('检测到内存泄漏');
return true;
}
return false;
}
cleanup() {
parser.destroy();
// 重新创建解析器
// parser = new HtmlLayoutParser();
}
}5xxx - 内部错误
这类错误表示系统内部问题。
5001 - WASM 模块未初始化
描述: 尝试使用未初始化的 WASM 模块。
解决方案:
typescript
// 确保初始化
async function ensureInitialized() {
if (!parser.isInitialized()) {
await parser.init();
}
}
// 使用前检查
await ensureInitialized();
const layouts = parser.parse(html, { viewportWidth: 800 });5002 - 内部状态错误
描述: 解析器内部状态不一致。
解决方案:
typescript
// 重置解析器
function resetParser() {
parser.destroy();
parser = new HtmlLayoutParser();
return parser.init();
}
// 在状态错误时重置
try {
const layouts = parser.parse(html, { viewportWidth: 800 });
} catch (error) {
if (error.message.includes('internal state')) {
console.warn('内部状态错误,重置解析器');
await resetParser();
const layouts = parser.parse(html, { viewportWidth: 800 });
}
}5003 - 系统资源不足
描述: 系统资源(如文件句柄、线程等)不足。
解决方案:
typescript
// 资源管理
class ResourceManager {
private activeOperations: number = 0;
private maxConcurrent: number = 5;
async executeWithLimit<T>(operation: () => Promise<T>): Promise<T> {
if (this.activeOperations >= this.maxConcurrent) {
await this.waitForSlot();
}
this.activeOperations++;
try {
return await operation();
} finally {
this.activeOperations--;
}
}
private async waitForSlot(): Promise<void> {
return new Promise(resolve => {
const check = () => {
if (this.activeOperations < this.maxConcurrent) {
resolve();
} else {
setTimeout(check, 100);
}
};
check();
});
}
}5004 - 未知内部错误
描述: 未分类的内部错误。
解决方案:
typescript
// 通用错误处理
function handleUnknownError(error: any) {
console.error('未知内部错误:', error);
// 收集诊断信息
const diagnostics = {
timestamp: new Date().toISOString(),
error: error.message,
stack: error.stack,
memory: parser.getTotalMemoryUsage(),
fonts: parser.getLoadedFonts().length,
environment: parser.getEnvironment(),
version: parser.getVersion()
};
console.log('诊断信息:', diagnostics);
// 可以发送到错误报告服务
// sendErrorReport(diagnostics);
}错误处理最佳实践
1. 分层错误处理
typescript
class ErrorHandler {
static handle(error: any, context: string): void {
const errorCode = error.code || 5004;
const category = Math.floor(errorCode / 1000);
switch (category) {
case 1:
this.handleInputError(error, context);
break;
case 2:
this.handleFontError(error, context);
break;
case 3:
this.handleParseError(error, context);
break;
case 4:
this.handleMemoryError(error, context);
break;
case 5:
this.handleInternalError(error, context);
break;
default:
this.handleUnknownError(error, context);
}
}
private static handleInputError(error: any, context: string): void {
console.warn(`输入错误 [${context}]:`, error.message);
// 尝试修复输入
}
// ... 其他处理方法
}2. 错误恢复策略
typescript
async function parseWithRecovery(html: string): Promise<CharLayout[] | null> {
const strategies = [
() => parser.parse(html, { viewportWidth: 800 }),
() => parser.parse(simplifyHTML(html), { viewportWidth: 800 }),
() => parser.parse(extractTextOnly(html), { viewportWidth: 800 }),
() => []
];
for (const strategy of strategies) {
try {
return strategy();
} catch (error) {
console.warn('策略失败,尝试下一个:', error.message);
}
}
return null;
}3. 错误监控和报告
typescript
class ErrorMonitor {
private errorCounts: Map<number, number> = new Map();
recordError(errorCode: number): void {
const count = this.errorCounts.get(errorCode) || 0;
this.errorCounts.set(errorCode, count + 1);
}
getTopErrors(): Array<{ code: number; count: number }> {
return Array.from(this.errorCounts.entries())
.map(([code, count]) => ({ code, count }))
.sort((a, b) => b.count - a.count)
.slice(0, 10);
}
generateReport(): string {
const topErrors = this.getTopErrors();
let report = '错误统计报告\n';
report += '================\n';
for (const { code, count } of topErrors) {
report += `错误 ${code}: ${count} 次\n`;
}
return report;
}
}