HTTP HEAD 请求超时的未知原因

发布于 2024-12-25 11:52:28 字数 5801 浏览 1 评论 0原文

我正在使用 ASP.NET 3.5 构建一个网站。该网站的一个区域显示了 28 个视频缩略图,这些缩略图是托管在另一台网络服务器上的 jpeg 格式。如果这些 jpeg 中的一个或多个不存在,我想向用户显示本地托管的默认图像,而不是浏览器中损坏的图像链接。

我实现此目的的方法是,每当呈现页面时,它都会对每个图像执行 HTTP HEAD 请求。如果我收到 200 OK 状态代码,则图像良好,我可以写出 .如果我收到 404 Not Found,那么我会写出

当然,如果我不想每次都对所有请求执行此操作,因此我实现了一个存储在应用程序级别的缓存图像状态对象列表,以便所有用户每 5 分钟只检查一次每个图像,但这与我的问题没有任何关系。

这看起来效果很好。我的问题是,对于特定图像,HTTP HEAD 请求因请求超时而失败。

我已将超时值设置得非常低,仅为 200 毫秒,这样就不会过多延迟页面渲染。这个超时对于大多数图像来说似乎都很好,我尝试过在调试过程中尝试并增加这个超时,但即使它是 10 秒或更长,也没有什么区别。

我写了一个日志文件来查看发生了什么,这就是我得到的结果(为了澄清和匿名而进行了编辑):

14:24:56.799|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/505C3080-EB4F-6CAE-60F8-B97F77A43A47/videothumb.jpg]]
14:24:57.356|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/66E2C916-EEB1-21D9-E7CB-08307CEF0C10/videothumb.jpg]]
14:24:57.914|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/905C3D99-C530-46D1-6B2B-63812680A884/videothumb.jpg]]
...
14:24:58.470|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/1CE0B04D-114A-911F-3833-D9E66FDF671F/videothumb.jpg]]
14:24:59.027|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/C3D7B5D7-85F2-BF12-E32E-368C1CB45F93/videothumb.jpg]]
14:25:11.852|ERROR|[HTTP HEAD CHECK ERROR [http://media.server.com/adpm/BED71AD0-2FA5-EA54-0B03-03D139E9242E/videothumb.jpg]] The operation has timed out
Source: System
Target Site: System.Net.WebResponse GetResponse()
Stack Trace:    at System.Net.HttpWebRequest.GetResponse()
   at MyProject.ApplicationCacheManager.ImageExists(String ImageURL, Boolean UseCache) in d:\Development\MyProject\trunk\src\Web\App_Code\Common\ApplicationCacheManager.cs:line 62

14:25:12.565|ERROR|[HTTP HEAD CHECK ERROR [http://media.server.com/adpm/92399E61-81A6-E7B3-4562-21793D193528/videothumb.jpg]] The operation has timed out
Source: System
Target Site: System.Net.WebResponse GetResponse()
Stack Trace:    at System.Net.HttpWebRequest.GetResponse()
   at MyProject.ApplicationCacheManager.ImageExists(String ImageURL, Boolean UseCache) in d:\Development\MyProject\trunk\src\Web\App_Code\Common\ApplicationCacheManager.cs:line 62

14:25:13.282|ERROR|[HTTP HEAD CHECK ERROR [http://media.server.com/adpm/7728C3B6-69C8-EFAA-FC9F-DAE70E1439F9/videothumb.jpg]] The operation has timed out
Source: System
Target Site: System.Net.WebResponse GetResponse()
Stack Trace:    at System.Net.HttpWebRequest.GetResponse()
   at MyProject.ApplicationCacheManager.ImageExists(String ImageURL, Boolean UseCache) in d:\Development\MyProject\trunk\src\Web\App_Code\Common\ApplicationCacheManager.cs:line 62

如您所见,前 25 个 HEAD 请求有效,而最后 3 个则无效。总是最后三个。

如果我将失败的 HEAD 请求 URL 之一粘贴到网络浏览器中:http://media.server.com/adpm/BED71AD0-2FA5-EA54-0B03-03D139E9242E/videothumb.jpg,它会加载图像没有问题。

为了尝试弄清楚这里发生了什么,我使用 Wireshark 捕获发送到托管图像的网络服务器的所有 HTTP 请求。对于我给出的日志示例,我可以看到 25 个 HEAD 请求,其中 25 个请求成功,但 3 个失败的请求没有出现在wireshark 跟踪中。

除了图像具有不同的视觉内容之外,一张图像与下一张图像没有区别。

为了消除 URL 本身的任何问题(即使它可以在浏览器中工作),我通过将第一个图像之一与最后失败的三个图像之一交换来更改顺序。当我这样做时,以前失败的问题就消失了,而被推到列表末尾的问题则开始失败。


所以我想我可以从上面推断出,当快速连续发生超过25个HEAD请求时,无论具体的URL是什么,后续的HEAD请求都会失败。我还知道问题出在 IIS 服务器上,而不是远程图像托管服务器上,因为 Wireshark 跟踪中缺少前 25 个请求。

我用来执行 HEAD 请求的代码片段如下所示。任何人都可以给我任何关于可能出现问题的建议吗?我尝试了请求标头值的各种不同组合,但它们似乎都没有任何区别。我的直觉是,某个 IIS 设置将任何对 ASP.NET 页面的请求中的并发 HttpWebRequest 数量限制为 25。

        try {
            HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(ImageURL);
            hwr.Method = "HEAD";
            hwr.KeepAlive = false;
            hwr.AllowAutoRedirect = false;
            hwr.Accept = "image/jpeg";
            hwr.Timeout = 200;
            hwr.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.Reload);
            //hwr.Connection = "close";

            HttpWebResponse hwr_result = (HttpWebResponse)hwr.GetResponse();
            if (hwr_result.StatusCode == HttpStatusCode.OK) {

                Diagnostics.Diags.Debug("HTTP HEAD CHECK OK [" + ImageURL + "]", HttpContext.Current.Request);

                // EXISTENCE CONFIRMED - ADD TO CACHE
                if (UseCache) {
                    _ImageExists.Value.RemoveAll(ie => ie.ImageURL == ImageURL);
                    _ImageExists.Value.Add(new ImageExistenceCheck() { ImageURL = ImageURL, Found = true, CacheExpiry = DateTime.Now.AddMinutes(5) });
                }

                // RETURN TRUE
                return true;

            } else if (hwr_result.StatusCode == HttpStatusCode.NotFound) {
                throw new WebException("404");
            } else {
                throw new WebException("ERROR");
            }            

        } catch (WebException ex) {
            if (ex.Message.Contains("404")) {

                Diagnostics.Diags.Debug("HTTP HEAD CHECK NOT FOUND [" + ImageURL + "]", HttpContext.Current.Request);

                // NON-EXISTENCE CONFIRMED - ADD TO CACHE
                if (UseCache) {
                    _ImageExists.Value.RemoveAll(ie => ie.ImageURL == ImageURL);
                    _ImageExists.Value.Add(new ImageExistenceCheck() { ImageURL = ImageURL, Found = false, CacheExpiry = DateTime.Now.AddMinutes(5) });
                }

                return false;

            } else {

                Diagnostics.Diags.Error(HttpContext.Current.Request, "HTTP HEAD CHECK ERROR [" + ImageURL + "]", ex);

                // ASSUME IMAGE IS OK
                return true;
            }

        } catch (Exception ex) {
            Diagnostics.Diags.Error(HttpContext.Current.Request, "GENERAL CHECK ERROR [" + ImageURL + "]", ex);

            // ASSUME IMAGE IS OK
            return true;
        }

I'm using ASP.NET 3.5 to build a website. One area of the website shows 28 video thumbnail images, which are jpeg's hosted on another webserver. If one or more of these jpegs do not exist, I want to display a locally hosted default image to the user, rather than a broken image link in the browser.

The approach I have taken to implement this is whenever the page is rendered it will perform an HTTP HEAD request to each of the images. If I get a 200 OK status code back, then the image is good and I can write out <img src="http://media.server.com/media/123456789.jpg" />. If I get a 404 Not Found, then I write out <img src="/images/defaultthumb.jpg" />.

If course I don't want to do this every time for all requests, and so I've implemented a list of cached image status objects stored at application level so that each image is only checked once every 5 minutes across all users, but this doesn't really have any bearing on my issue.

This seems to work very well. My problem is that for specific images, the HTTP HEAD request fails with Request Timed Out.

I have set my timeout value very low to only 200ms so that is doesn't delay the page rendering too much. This timeout seems to be fine for most of the images, and I've tried playing around and increasing this during debugging, but it makes no difference even if it's 10s or more.

I write out a log file to see whats happening, and this is what I get (edited for clarify and anonymity):

14:24:56.799|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/505C3080-EB4F-6CAE-60F8-B97F77A43A47/videothumb.jpg]]
14:24:57.356|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/66E2C916-EEB1-21D9-E7CB-08307CEF0C10/videothumb.jpg]]
14:24:57.914|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/905C3D99-C530-46D1-6B2B-63812680A884/videothumb.jpg]]
...
14:24:58.470|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/1CE0B04D-114A-911F-3833-D9E66FDF671F/videothumb.jpg]]
14:24:59.027|DEBUG|[HTTP HEAD CHECK OK [http://media.server.com/adpm/C3D7B5D7-85F2-BF12-E32E-368C1CB45F93/videothumb.jpg]]
14:25:11.852|ERROR|[HTTP HEAD CHECK ERROR [http://media.server.com/adpm/BED71AD0-2FA5-EA54-0B03-03D139E9242E/videothumb.jpg]] The operation has timed out
Source: System
Target Site: System.Net.WebResponse GetResponse()
Stack Trace:    at System.Net.HttpWebRequest.GetResponse()
   at MyProject.ApplicationCacheManager.ImageExists(String ImageURL, Boolean UseCache) in d:\Development\MyProject\trunk\src\Web\App_Code\Common\ApplicationCacheManager.cs:line 62

14:25:12.565|ERROR|[HTTP HEAD CHECK ERROR [http://media.server.com/adpm/92399E61-81A6-E7B3-4562-21793D193528/videothumb.jpg]] The operation has timed out
Source: System
Target Site: System.Net.WebResponse GetResponse()
Stack Trace:    at System.Net.HttpWebRequest.GetResponse()
   at MyProject.ApplicationCacheManager.ImageExists(String ImageURL, Boolean UseCache) in d:\Development\MyProject\trunk\src\Web\App_Code\Common\ApplicationCacheManager.cs:line 62

14:25:13.282|ERROR|[HTTP HEAD CHECK ERROR [http://media.server.com/adpm/7728C3B6-69C8-EFAA-FC9F-DAE70E1439F9/videothumb.jpg]] The operation has timed out
Source: System
Target Site: System.Net.WebResponse GetResponse()
Stack Trace:    at System.Net.HttpWebRequest.GetResponse()
   at MyProject.ApplicationCacheManager.ImageExists(String ImageURL, Boolean UseCache) in d:\Development\MyProject\trunk\src\Web\App_Code\Common\ApplicationCacheManager.cs:line 62

As you can see, the first 25 HEAD requests work, and the final 3 do not. It's always the last three.

If I paste one of the failed HEAD request URLs into a web browser: http://media.server.com/adpm/BED71AD0-2FA5-EA54-0B03-03D139E9242E/videothumb.jpg, it loads the image with no problems.

To try to work out what is happening here, I used Wireshark to capture all of the HTTP requests that are sent to the webserver hosting the images. For the log example I've given, I can see 25 HEAD requests for the 25 that were successful, but the 3 that failed do NOT appear in the wireshark trace.

Other than the images having different visual content, there is no difference from one image to the next.

To eliminate any problems with the URL itself (even though it works in a browser) I changed the order by switching one of the first images with one of the last failed three. When I do this, the problem goes away for the one that used to fail, and starts failing for the one that was bumped down to the end of the list.


So I think I can deduce from the above that when more than 25 HEAD requests occur in quick succession, subsequent HEAD requests fail regardless of the specific URL. I also know that the issue is on the IIS server rather than the remote image hosting server, due to the lack of requests in the Wireshark trace beyond the first 25.

The code snippet I'm using to perform the HEAD requests is shown below. Can anyone give me any suggestions as to what might be the problem? I've tried various different combinations of request header values, but none of them seem to make any difference. My gut feeling is there is some IIS setting somewhere that limits the number of concurrent HttpWebRequests's to 25 in any one request to an ASP.NET page.

        try {
            HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(ImageURL);
            hwr.Method = "HEAD";
            hwr.KeepAlive = false;
            hwr.AllowAutoRedirect = false;
            hwr.Accept = "image/jpeg";
            hwr.Timeout = 200;
            hwr.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.Reload);
            //hwr.Connection = "close";

            HttpWebResponse hwr_result = (HttpWebResponse)hwr.GetResponse();
            if (hwr_result.StatusCode == HttpStatusCode.OK) {

                Diagnostics.Diags.Debug("HTTP HEAD CHECK OK [" + ImageURL + "]", HttpContext.Current.Request);

                // EXISTENCE CONFIRMED - ADD TO CACHE
                if (UseCache) {
                    _ImageExists.Value.RemoveAll(ie => ie.ImageURL == ImageURL);
                    _ImageExists.Value.Add(new ImageExistenceCheck() { ImageURL = ImageURL, Found = true, CacheExpiry = DateTime.Now.AddMinutes(5) });
                }

                // RETURN TRUE
                return true;

            } else if (hwr_result.StatusCode == HttpStatusCode.NotFound) {
                throw new WebException("404");
            } else {
                throw new WebException("ERROR");
            }            

        } catch (WebException ex) {
            if (ex.Message.Contains("404")) {

                Diagnostics.Diags.Debug("HTTP HEAD CHECK NOT FOUND [" + ImageURL + "]", HttpContext.Current.Request);

                // NON-EXISTENCE CONFIRMED - ADD TO CACHE
                if (UseCache) {
                    _ImageExists.Value.RemoveAll(ie => ie.ImageURL == ImageURL);
                    _ImageExists.Value.Add(new ImageExistenceCheck() { ImageURL = ImageURL, Found = false, CacheExpiry = DateTime.Now.AddMinutes(5) });
                }

                return false;

            } else {

                Diagnostics.Diags.Error(HttpContext.Current.Request, "HTTP HEAD CHECK ERROR [" + ImageURL + "]", ex);

                // ASSUME IMAGE IS OK
                return true;
            }

        } catch (Exception ex) {
            Diagnostics.Diags.Error(HttpContext.Current.Request, "GENERAL CHECK ERROR [" + ImageURL + "]", ex);

            // ASSUME IMAGE IS OK
            return true;
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

萌能量女王 2025-01-01 11:52:28

我自己已经解决了这个问题。问题确实是允许的连接数,默认设置为 24。

就我而言,我将仅在 MyHttpWebRequest.ServicePoint.CurrentConnections 小于 10 时执行图像检查。

要增加最大限制,只需设置 ServicePointManager.DefaultConnectionLimit您需要的并发连接数。

可能对某些人有所帮助的另一种选择是减少空闲时间,即连接等待直至自行破坏的时间。要更改此设置,您需要将 MyHttpWebRequest.ServicePoint.MaxIdleTime 设置为超时值(以毫秒为单位)。

I have solved this myself. The problem was indeed the number of allowed connections, which was set to 24 by default.

In my case, I am going to only perform the image check if the MyHttpWebRequest.ServicePoint.CurrentConnections is less than 10.

To increase the max limit, just set ServicePointManager.DefaultConnectionLimit to the number of concurrent connections you require.

An alternative which may help some people would be to reduce the idle time that is the time a connection waits until it destroys itself. To change this, you need to set MyHttpWebRequest.ServicePoint.MaxIdleTime to the timeout value in milliseconds.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文