Skip to content

Обработка ошибок

Классификация ошибок

Ошибки библиотеки HTML делятся на следующие категории:

КатегорияСигнатурные ошибкиОписание
Ошибки вводаErrInputTooLarge, ErrInvalidHTMLПроблемы с содержимым ввода
Ошибки конфигурацииErrInvalidConfig, ErrMultipleConfigsПроблемы конфигурации
Файловые ошибкиErrFileNotFound, ErrInvalidFilePathПроблемы файловых операций
Ошибки обработкиErrProcessingTimeout, ErrMaxDepthExceededПроблемы в процессе обработки
Системные ошибкиErrProcessorClosed, ErrInternalPanicПроблемы внутреннего состояния

Паттерн errors.Is

Использование errors.Is для определения типа ошибки:

go
result, err := html.Extract(data)
if err != nil {
    switch {
    case errors.Is(err, html.ErrInputTooLarge):
        slog.Warn("Ввод слишком большой, уменьшите размер документа")
    case errors.Is(err, html.ErrInvalidHTML):
        slog.Warn("Некорректный HTML, проверьте ввод")
    case errors.Is(err, html.ErrProcessingTimeout):
        slog.Warn("Тайм-аут обработки, документ может быть слишком сложным")
    case errors.Is(err, html.ErrFileNotFound):
        slog.Warn("Файл не существует")
    case errors.Is(err, html.ErrMaxDepthExceeded):
        slog.Warn("Глубина DOM слишком велика, возможно злонамеренная конструкция")
    case errors.Is(err, html.ErrInternalPanic):
        slog.Error("Восстановление после внутренней паники, пожалуйста, сообщите об этой проблеме")
    default:
        slog.Error("Неизвестная ошибка", "err", err)
    }
}

Паттерн errors.As

Извлечение структурированной информации об ошибках:

go
var inputErr *html.InputError
var configErr *html.ConfigError
var fileErr *html.FileError

if errors.As(err, &inputErr) {
    fmt.Printf("Размер %d превышает лимит %d\n", inputErr.Size, inputErr.MaxSize)
}

if errors.As(err, &configErr) {
    fmt.Printf("Поле %s значение %v некорректно: %s\n", configErr.Field, configErr.Value, configErr.Message)
}

if errors.As(err, &fileErr) {
    fmt.Printf("Файловая операция: %s\n", fileErr.SafePath())
}

Отмена через контекст

Использование версий ExtractWithContext для поддержки отмены:

go
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

result, err := html.ExtractWithContext(ctx, data)
if err != nil {
    switch {
    case errors.Is(err, html.ErrProcessingTimeout):
        // Внутренний тайм-аут ProcessingTimeout (в этот момент ctx.Err() может быть nil)
    case ctx.Err() == context.DeadlineExceeded:
        // Дедлайн пользовательского контекста истёк
    case ctx.Err() == context.Canceled:
        // Ручная отмена
    default:
        // Другие ошибки (ErrInvalidHTML, ErrInputTooLarge и т.д.)
        slog.Error("Извлечение не удалось", "err", err)
    }
}

Ошибки пакетной обработки

Результаты пакетной обработки содержат как успешные, так и неудачные операции:

go
batch := p.ExtractBatch(pages)

for i, err := range batch.Errors {
    if err != nil {
        fmt.Printf("Элемент %d не удался: %v\n", i, err)
    }
}

fmt.Printf("Успешно: %d, Неудачно: %d, Отменено: %d\n",
    batch.Success, batch.Failed, batch.Cancelled)