Как предотвратить исключение Stackoverflow в HtmlAgilityPack для очень плохого html

c# html-agility-pack stack-overflow

Вопрос

Я использую HtmlAgilityPack в MVC 5 Web Api. 99.99% времени, проблем нет ... загружает сайты, и я разбираю их, чтобы извлечь текст, который я хочу. Мой API может поражать несколько сотен тысяч раз в день без проблем. В прошлом году он счастливо обработал более 2 миллионов хитов за 24 часа ...

Иногда, однако, ужасно сформированные веб-сайты вызывают ошибку 500 ответа. Затем все последующие запросы получают 500 ошибок, и сайт становится полностью непригодным. Единственным решением в этом случае является перезапуск веб-приложения. Сайт размещен на Windows Azure. Я использовал нагруженные сбалансированные большие экземпляры, и после того, как CPU всплескается, он остается высоким. В прошлом это отлично работало на одном экземпляре Medium Azure (2 ядра / 3,5 ГБ оперативной памяти)

Ошибка - это Stackoverflow ..., которую я знаю, я не могу поймать.

Обратите внимание, что этот код НЕ запускает консольное приложение

HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load("http://nursingandmidwiferycareersni.com/");            
Console.Write(doc.DocumentNode.InnerText);

... но это определенно приведет к сбою веб-приложения MVC.

Однако в простом веб-приложении MVC я могу воспроизвести ошибку stackoverflow с таким сайтом, как http://nursingandmidwiferycareersni.com/ . Если вы поместите http://nursingandmidwiferycareersni.com/ в https://validator.w3.org Вам удастся получить внутреннюю ошибку сервера на validator.w3.org!

Я буду взламывать исходный код HAP, если это необходимо, чтобы обойти это ... В настоящее время я просто использую пакет Nuget.

Возможно ли предотвратить переполнение стека в HAP?
Или есть способ проверить ужасный html и предотвратить возникновение сбоя в первую очередь?

Популярные ответы

Дайте что - то подобное попробовать, где ParseHtml метод и ParsedHtml типа являются только заполнители для вас , чтобы заполнить в:

public async Task<ParsedHtml> TryParseHtml(
    string untrustedHtml,
    CancellationToken cancellationToken)
{
    var tcs = new TaskCompletionSource<ParsedHtml>();

    var thread = new Thread(() =>
    {
        ParsedHtml result = ParseHtml(untrustedHtml);
        tcs.TrySetResult(result);
    });
    thread.Start();

    using (cancellationToken.Register(() => tcs.TrySetCanceled()))
    {
        try
        {
            return await tcs.Task;
        }
        catch (OperationCanceledException)
        {
            thread.Abort();
            throw;
        }
    }
}

Идея может быть расширена, чтобы быть более эффективной за счет повторного использования потоков в успешном случае, вместо того, чтобы стрелять и разрывать нить для каждой HTML-страницы.



Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow