【问题标题】:How to prevent Stackoverflow Exception in HtmlAgilityPack for very bad html如何防止 HtmlAgilityPack 中的 Stackoverflow 异常对于非常糟糕的 html
【发布时间】:2015-05-28 01:52:53
【问题描述】:

我在 MVC 5 Web Api 中使用 HtmlAgilityPack。 99.99% 的时间都没有问题……网站加载并解析它们以提取我想要的文本。我的 API 每天可以被点击几十万次而没有问题。它在过去 24 小时内愉快地处理了超过 200 万次点击...

但是,有时,格式错误的网站会导致错误 500 响应。然后所有后续请求都会收到 500 个错误,并且该站点变得完全无法使用。在这种情况下,唯一的解决方案是重新启动 Web 应用程序。该站点托管在 Windows Azure 上。我使用了负载平衡的大型实例,一旦 CPU 达到峰值,它就会保持在高位。过去,这在单个中型 Azure 实例(2 核/3.5 GB RAM)上运行良好

错误是 Stackoverflow... 我知道我无法捕捉到。

请注意,此代码不会使控制台应用程序崩溃

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

...但它肯定会使 MVC Web 应用程序崩溃。

但是,在一个简单的 MVC Web 应用程序中,我可以使用 http://nursingandmidwiferycareersni.com/ 之类的站点重现 stackoverflow 错误。如果您将http://nursingandmidwiferycareersni.com/ 放入https://validator.w3.org 您将设法在validator.w3.org 上获得内部服务器错误!

如有必要,我将对 HAP 源代码进行 hack 以解决此问题...目前我只使用 Nuget 包。

是否可以防止在 HAP 中发生 stackoverflow?
或者有没有办法检查糟糕的 html 并首先防止崩溃发生?

【问题讨论】:

  • 我的第一个想法是简单地保留 HTML 格式错误的网站的黑名单。
  • 您也可以尝试在其自己的线程上解析不受信任的 HTML,然后使用 Thread.Abort 在解析某些 HTML 的时间超过超时时间时将其杀死。
  • 我试图在 chrome 中查看页面的源代码,只是出于好奇,chrome 本身在 [查看源代码](查看源代码:nursingandmidwiferycareersni.com)方面存在严重问题。该站点有 211.023 行 - 大部分似乎是空白。
  • @TimothyShields 我通过查看源代码设法使 Chrome 崩溃。不幸的是,您建议保留网站黑名单是不可能的 - 我可以使用 HAP 扫描数百万个新域。至于中止线程,这是一个选项,但不是我的首选方法。我目前的 Web 请求超时 6000 毫秒。

标签: c# stack-overflow html-agility-pack


【解决方案1】:

试试这样的东西,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 页面启动和拆除一个线程,可以将这个想法扩展为更有效。

【讨论】:

  • 请注意,StackOverflowException 会导致进程崩溃,并且如果使用正确的 HTML,它可能会立即发生。如此短的产生一个新进程,你总是有可能导致当前进程崩溃。
猜你喜欢
  • 2012-05-06
  • 2010-09-16
  • 2017-01-25
  • 2018-06-27
  • 1970-01-01
  • 1970-01-01
  • 2015-05-11
  • 2021-03-11
  • 2018-08-17
相关资源
最近更新 更多