【问题标题】:HttpWebRequest vs Webclient (Special scenario)HttpWebRequest vs Webclient(特殊场景)
【发布时间】:2012-08-21 13:01:14
【问题描述】:

我知道这个问题已经在这个thread 中得到了回答,但我似乎找不到详细信息。

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

我似乎不知道应该使用HttpWebRequest 还是WebClient 来下载html 页面源并进行比较?在我的情况下,您认为什么是理想的解决方案?速度和可靠性兼具:)

【问题讨论】:

  • 适合什么?速度?可读性?还有什么?
  • 速度和可靠性兼备:)...如果我必须选择一个,我会追求效率

标签: c# html http


【解决方案1】:

我会选择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;    
    }
}

如果页面在dateTime 日期后被修改,则此方法应返回true,否则应返回falseGetResponse 方法将抛出 WebException 如果您发出 HEAD 请求并且服务器返回 304 - NOT MODIFIED(这有点不幸)。我们必须确保它不是其他网络连接问题,这就是为什么我检查网络异常状态和响应的 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,因为他对这项技术几乎没有什么好的建议。

【讨论】:

  • 您能否发布一个“文件未更改”场景的示例?
  • @Free Styler - 有一个 HTTP 状态码 - 304 Not Modified
  • @Free Styler:我将它添加到我的答案中
  • @Free Styler:我想你必须在你的请求中添加一些额外的信息。看看IfModifiedSince属性:msdn.microsoft.com/en-us/library/…
  • @Free Styler:网络服务器可以为某些页面或整个站点关闭此功能。在这种情况下,我想你必须下载整个东西才能检查
【解决方案2】:

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

Dyppl 的回应通常是很好的建议,以及我解决此问题的方式。但是,您应该记住一些事项。

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

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

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

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

【讨论】:

  • 嗨,吉姆,感谢您的回复。我的问题是为什么我不应该发出一个 GET 请求并检查内容长度是否有变化,而不是发出两个请求?
  • @Free Styler:因为当您发出 GET 请求时,服务器将开始将数据流式传输给您。即使您实际上没有读取数据,服务器也会将其发送并到达您的计算机。您最终会下载大量不需要的数据。如果您偶尔检查几页,这不是问题,但如果您谈论的是每秒检查 30 页,则需要考虑一下。
  • 谢谢,这些都是很好的建议,我在回答中添加了指向您帖子的链接。我不认为使用HEAD 是一个很大的问题,因为您只在 has 发生更改时发出 2 个请求,这应该是一个相对罕见的事件(尽管这完全是特定于域的) .
猜你喜欢
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-08
  • 2020-06-03
  • 2020-04-17
相关资源
最近更新 更多