HttpWebRequest vs Webclient(特殊场景)

时间:2011-06-04 21:21:14

标签: c# html http

我知道此问题已在此thread中得到解答,但我似乎无法找到详细信息。

在我的场景中,我正在构建一个控制台应用程序,它将密切关注任何更改的html页面源。如果发生任何更新/更改,我将执行进一步的操作。此外,我还会在每1秒后执行一次请求,或者在上一次请求完成后立即执行请求。

我似乎无法弄清楚我应该使用HttpWebRequestWebClient来下载html页面源并执行比较吗?在我看来,您认为什么是理想的解决方案?速度和可靠性:)

2 个答案:

答案 0 :(得分:14)

我会选择HttpWebRequst,因为它不是抽象的,而且可以让你轻松掌握HTTP参数。例如,如果服务器返回“文件未更改”,则可以选择不下载整个页面。

如果您向请求添加一些参数,例如IfModifiedSince(可能是HEAD或GET请求),服务器可能会返回响应代码 304 - NOT MODIFIED 。有关详细说明,请参阅description of caching in HTTP

重点是确保自上次提取页面以来实际修改完整页面时才下载完整页面。大多数情况下它不会被更改(我想,如果不知道你的域名就无法确定),所以你只需要从服务器获得一个轻量级响应,它只是说“这里没有任何改变”。

更新代码示例演示IfModifiedSince属性的使用:

bool IsResourceModified(string url, DateTime dateTime) {            
    try {
        var request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
        request.IfModifiedSince = dateTime;
        request.Method = "HEAD";
        var response = (HttpWebResponse)request.GetResponse();

        return true;
    }
    catch(WebException ex) {
        if(ex.Status != WebExceptionStatus.ProtocolError)
            throw;

        var response = (HttpWebResponse)ex.Response;
        if(response.StatusCode != HttpStatusCode.NotModified)
            throw;

        return false;    
    }
}

如果页面在true日期后被修改,则此方法应返回dateTime,如果不是,则false。如果您发出HEAD请求,GetResponse方法将抛出WebException,并且服务器返回 304 - NOT MODIFIED (这有点不幸)。我们必须确保它不是其他一些Web连接问题,这就是为什么我检查Web异常的状态和响应中的HTTP状态。如果有任何其他原因导致异常,我们就把它扔得更远。

Console.WriteLine(IsResourceModified("http://example.com", new DateTime(2009)));
Console.WriteLine(IsResourceModified("http://example.com", DateTime.Now));

此示例代码生成输出:

True
False

注意:请务必阅读Jim Mischel's addition to this answer,因为他对此技术提出的建议很少。

答案 1 :(得分:9)

我打算将此作为对@ Dyppl回复的评论,但它变得太长了。

Dyppl的反应通常是很好的建议,以及我将如何解决这个问题。但是,您应该记住一些事项。

首先,没有理由进行HEAD请求,如果页面已被修改,则后跟GET。您可以使用GET标头设置IfModifiedSince,服务器将返回整个页面或304.首先执行HEAD,然后执行'GET`,最终向服务器发出两个请求,这违反了条件请求的大部分目的。

其次,您应该将IfModifiedSince属性设置为上一个响应返回的LastModified值(即HttpWebResponse.LastModified),因为服务器的时间可能与您的计算机无法同步。此外,我发现大部分网站,特别是那些生成内容的网站(如WordPress博客)都存在。它们始终在LastModified标题中返回当前日期/时间。因此,对这些网站进行If-Modified-Since检查没有任何好处。

如果您知道网站位于并始终返回当前日期/时间,则可以跟踪下载时从页面返回的ContentLength标题。然后,当您想要检查页面是否已更改时,请执行HEAD请求并使用保存的值检查返回的ContentLength标头。如果它们匹配,则页面不太可能发生变化。如果它们不匹配,请执行GET请求更新您的网页副本并保留新的ContentLength

如果页面已更改,此技术的缺点是需要两个请求。它在所有服务器上也不是100%可靠。有些会为ContentLength请求返回不同的HEAD,而有些则根本不返回有效的ContentLength。也就是说,我发现它对大量网站都有效。