【发布时间】:2012-01-09 15:41:54
【问题描述】:
我正在使用 ASP.NET 3.5 构建网站。该网站的一个区域显示了 28 个视频缩略图图像,这些图像是 jpeg 托管在另一个网络服务器上的。如果这些 jpeg 中的一个或多个不存在,我想向用户显示本地托管的默认图像,而不是浏览器中损坏的图像链接。
我采取的实现方法是,每当呈现页面时,它都会对每个图像执行 HTTP HEAD 请求。如果我得到 200 OK 状态码,那么图像很好,我可以写出<img src="http://media.server.com/media/123456789.jpg" />。如果我得到一个 404 Not Found,那么我写出<img src="/images/defaultthumb.jpg" />。
如果我不想每次都对所有请求都执行此操作,因此我实现了存储在应用程序级别的缓存图像状态对象列表,以便所有用户每 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 之一粘贴到 Web 浏览器: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 请求的代码 sn-p 如下所示。谁能给我任何关于可能是什么问题的建议?我尝试了各种不同的请求标头值组合,但它们似乎都没有任何区别。我的直觉是某处的某些 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;
}
【问题讨论】:
标签: asp.net http iis httpwebrequest head