WebRequest "HEAD"轻量级替代方案

7

最近我发现下面这段代码在某些网站上无法正常使用,比如IMDB.com。

class Program
    {
        static void Main(string[] args)
        {
            try
            {
                System.Net.WebRequest wc = System.Net.WebRequest.Create("http://www.imdb.com"); //args[0]);

                ((HttpWebRequest)wc).UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.153.1 Safari/525.19";
                wc.Timeout = 1000;
                wc.Method = "HEAD";
                WebResponse res = wc.GetResponse();
                var streamReader = new System.IO.StreamReader(res.GetResponseStream());

                Console.WriteLine(streamReader.ReadToEnd());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

它返回一个HTTP 405(方法不允许)错误。我的问题是,我使用与上面非常相似的代码来检查一个链接是否有效,绝大多数情况下它都能正常工作。我可以将其切换为method等于GET,然后它就能工作了(但需要增加超时时间),但这会使速度减慢一个数量级。我认为405响应是IMDB服务器端的配置问题。 有没有一种轻量级的方法在.NET中实现与上述相同的功能?或者,有没有一种方法修复上面的代码,使之成为能够在imdb上正常工作的GET请求?

1
我不得不增加超时时间,但你上面发布的代码对我有效。将其更改为POST没有意义,因为您没有任何要发布的数据。而且您的标题谈论HEAD,但您并没有进行HEAD请求。请澄清问题是什么,因为您的“错误”代码运行良好。 - Joe White
哎呀,标题里真的有一个愚蠢的打字错误。现在已经修复了...这是一个典型的例子,想着一件事情,却打出另一件事情。当你运行上面的代码时,你没有得到405响应吗?编辑:好的,我意识到我的代码也有缺陷。上面的内容是我想发布的内容,并进行了编辑以产生405错误(并且更有意义...)。 - Serapth
3个回答

6

使用套接字(而不是 HttpRequestWebClient)自己打开连接,并在读取状态码后立即关闭流。幸运的是,状态码出现在响应流的顶部附近 :)


4

你需要澄清“轻量级”的含义,你想要实现什么目的?

能否使用GET / POST / HEAD / DELETE等取决于URL以及在运行在该URL的服务器上配置的应用程序。

如果你只是想查看是否可以建立连接而不实际下载内容,则可以尝试使用sockets连接到端口80,但是仅仅通过更改HTTP方法并没有可靠或普遍支持的方法。


基本上,我现在使用HEAD请求的目的是:a)检查网站是否真实存在;b)如果网站存在,则验证其中每个链接是否真实存在(因此包括每个图像、样式表等)。因此,在某些图像密集的页面上,它可能会被调用数百次。因此,轻量级主要指网络流量。 - Serapth
1
对于带宽来说,我所能想到的唯一更轻量的方法是使用套接字手动构造HTTP请求,获取足够的响应以确定HTTP状态码,然后关闭连接。 - Daniel Schaffer
手工制作HTTP是否可以避免405状态结果?编辑:呃,我应该说状态结果,我想从技术上讲,HTTP 405实际上并不是错误。只有少数几个站点返回405,我实际上不知道是什么部分导致了这种响应。现在,我假设它是HEAD请求,但我不确定。 - Serapth
HEAD请求是导致问题的原因。我所说的手工制作HTTP请求是指使用GET请求,这是服务器所期望的,但由于您可以控制下载内容,因此您可以仅下载响应头,然后在下载正文之前终止连接。 - Daniel Schaffer

4
如果HEAD返回405,则表示服务器不支持HEAD(至少对于该URL),您需要退回到GET。大多数网站应该支持HEAD,因此您可能希望默认使用HEAD,但是如果它抛出405,则可以为该域退回到GET。或者您可能想尝试每个请求首先使用HEAD;YMMV。
如果服务器要求GET并且您想减少网络流量,则可以尝试进行有条件的GET和/或部分GET(请参见例如RFC2616)。我从未尝试过使用WebRequest进行这些操作,但我认为它允许您添加自定义的传出HTTP标头,因此您应该能够完成此操作。
此外,请不要忘记,如果您正在编写蜘蛛程序(显然是这样),则应遵守服务器的robots.txt,并且最好将您的请求限制为每2秒一个请求,以便您不会破坏服务器。

谢谢您的回复。实际上我并没有在写爬虫,最终产品更接近于一个浏览器而不是其他什么。我按照您之前建议的方式进行了操作(先进行HEAD请求,然后在405状态码时进行完整的GET请求),这是我目前的做法,但它并不是最优的。我将研究一下部分GET请求,那可能会更完美。谢谢。 - Serapth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接