常量与错误
默认配置常量
| 常量 | 类型 | 值 | 说明 |
|---|---|---|---|
DefaultMaxInputSize | int | 52428800 | 最大输入大小 (50MB) |
DefaultMaxCacheEntries | int | 2000 | 缓存最大条目 |
DefaultWorkerPoolSize | int | 4 | 工作池大小 |
DefaultCacheTTL | time.Duration | 1h | 缓存过期时间 |
DefaultCacheCleanup | time.Duration | 5m | 缓存清理间隔 |
DefaultMaxDepth | int | 500 | 最大 DOM 深度 |
DefaultProcessingTimeout | time.Duration | 30s | 处理超时时间 |
审计常量
审计事件类型
| 常量 | 值 | 说明 |
|---|---|---|
AuditEventBlockedTag | "blocked_tag" | 被阻止的标签 |
AuditEventBlockedAttr | "blocked_attr" | 被阻止的属性 |
AuditEventBlockedURL | "blocked_url" | 被阻止的 URL |
AuditEventInputViolation | "input_violation" | 输入违规 |
AuditEventDepthViolation | "depth_violation" | 深度违规 |
AuditEventTimeout | "timeout" | 处理超时 |
AuditEventEncodingIssue | "encoding_issue" | 编码问题 |
AuditEventPathTraversal | "path_traversal" | 路径遍历尝试 |
审计级别
| 常量 | 类型 | 值 | 说明 |
|---|---|---|---|
AuditLevelInfo | AuditLevel | "info" | 信息级别 |
AuditLevelWarning | AuditLevel | "warning" | 警告级别 |
AuditLevelCritical | AuditLevel | "critical" | 严重级别 |
INFO
审计系统的详细用法和 Sink 类型详见 审计系统。
哨兵错误
| 错误 | 消息 | 说明 |
|---|---|---|
ErrInputTooLarge | html: input size exceeds maximum | 输入超过大小限制 |
ErrInvalidHTML | html: invalid HTML | 无效 HTML 内容 |
ErrProcessorClosed | html: processor closed | 处理器已关闭 |
ErrMaxDepthExceeded | html: max depth exceeded | 超过最大深度 |
ErrInvalidConfig | html: invalid config | 无效配置 |
ErrProcessingTimeout | html: processing timeout exceeded | 处理超时 |
ErrFileNotFound | html: file not found | 文件未找到 |
ErrInvalidFilePath | html: invalid file path | 无效文件路径 |
ErrInternalPanic | html: internal panic recovered | 内部恐慌已恢复 |
ErrMultipleConfigs | html: at most one Config may be provided | 最多一个 Config |
错误类型
InputError
输入相关错误,携带大小信息。
go
type InputError struct {
Op string // 操作名
Size int // 实际大小
MaxSize int // 最大限制
InputErr error // 原始错误
}
func (e *InputError) Error() string
func (e *InputError) Unwrap() error // → InputErr(非 nil 时)或 ErrInputTooLargeConfigError
配置验证错误,携带字段信息。
go
type ConfigError struct {
Field string // 字段名
Value any // 无效值
Message string // 错误描述
}
func (e *ConfigError) Error() string
func (e *ConfigError) Unwrap() error // → ErrInvalidConfigFileError
文件操作错误,自动截断路径防止泄露。
go
type FileError struct {
Op string // 操作名
Path string // 文件路径
FileErr error // 原始错误
}
func (e *FileError) Error() string // 安全输出(截断路径)
func (e *FileError) SafePath() string // 仅返回文件名
func (e *FileError) Unwrap() error // → ErrFileNotFound | 原始错误 | ErrInvalidFilePath
func (e *FileError) MarshalJSON() ([]byte, error) // 专为 HTTP API 响应场景:序列化为 JSON 返回客户端时经 SafePath() 截断 Path,防止文件系统路径泄露安全路径
FileError.Error() 和 SafePath() 都返回截断后的安全路径(仅文件名),防止路径泄露。内部调试需要完整路径时可直接访问 Path 字段。
内部限制常量
以下常量定义了库的运行时硬上限。它们非导出(小写开头),不可直接引用,但影响运行时行为——了解这些值有助于理解库的边界条件和错误场景。
配置上限
| 常量 | 值 | 说明 |
|---|---|---|
maxConfigInputSize | 52428800 (50MB) | MaxInputSize 配置上限;即便设置更大值也会被 Validate() 拒绝 |
maxConfigWorkerSize | 256 | WorkerPoolSize 配置上限 |
maxConfigDepth | 500 | MaxDepth 配置上限 |
maxConfigCacheEntries | 100000 | MaxCacheEntries 配置上限(≈100MB,按每条 1KB 估算) |
处理限制
| 常量 | 值 | 说明 |
|---|---|---|
maxBatchSize | 10000 | 单次批量最大项数;超限整批返回错误(非 panic) |
maxTimeoutGoroutines | 1000 | 全局并发超时 goroutine 上限;超限新请求直接返回 ErrProcessingTimeout |
maxHTMLForRegex | 1000000 (1MB) | 媒体 URL 正则扫描的 HTML 大小上限;超过此值跳过正则兜底(防 ReDoS) |
maxRegexMatches | 1000 | 单次正则扫描的最大匹配数;防止媒体密集页面产生过量分配 |
缓存 Key 生成
| 常量 | 值 | 说明 |
|---|---|---|
maxCacheKeySize | 65536 (64KB) | 完整哈希的内容大小阈值;超出此值切换到 5 点采样 |
cacheKeySample | 4096 | 大文档采样的总字节预算(5 点 × ~820 字节/点) |
为什么需要了解这些
这些常量解释了一些「为什么」:为什么超过 1MB 的 HTML 不再提取裸视频链接(ReDoS 防护)、为什么批量超过 10000 项整批失败(OOM 防护)、为什么 64KB 是缓存 Key 策略的分界线(哈希成本 vs 碰撞风险)。
错误处理模式
go
result, err := html.Extract(data)
if err != nil {
var inputErr *html.InputError
var configErr *html.ConfigError
var fileErr *html.FileError
switch {
case errors.Is(err, html.ErrInputTooLarge):
// 输入过大
case errors.Is(err, html.ErrInvalidHTML):
// 无效 HTML
case errors.Is(err, html.ErrFileNotFound):
// 文件不存在
case errors.As(err, &inputErr):
fmt.Printf("大小 %d 超过限制 %d\n", inputErr.Size, inputErr.MaxSize)
case errors.As(err, &configErr):
fmt.Printf("配置字段 %s 无效: %s\n", configErr.Field, configErr.Message)
case errors.As(err, &fileErr):
fmt.Printf("文件: %s\n", fileErr.SafePath())
}
}