我正在使用ASP.NET3.5构建一个网站。网站的一个区域显示28个视频缩略图,这些缩略图是jpeg格式的,位于另一个Web服务器上。如果其中一个或多个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请求失败,请求超时。
我把超时值设置得很低,只有200ms,这样就不会太多地延迟页面呈现。这个超时似乎对大多数图像来说都很好,我也试着在调试期间增加这个值,但即使是10s或更长时间也没有什么区别。
我写了一个日志文件,看看发生了什么,这是我得到的(编辑澄清和匿名):
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个无效,总是最后3个无效。
如果我将其中一个失败的HEAD请求URL粘贴到Web浏览器中:http://media.server.com/adpm/BED71AD0-2FA5-EA54-0B03-03D139E9242E/videothumb.jpg
,它加载图像没有任何问题。
为了弄清楚这里发生了什么,我使用Wireshark捕获了发送到托管图像的Web服务器的所有HTTP请求。对于我给出的日志示例,我可以看到25个HEAD请求中有25个成功,但3个失败的请求没有出现在Wireshark跟踪中。
除了具有不同视觉内容的图像之外,从一个图像到下一个图像没有差别。
为了消除URL本身的任何问题(即使它在浏览器中工作),我改变了顺序,将前三个失败的图像中的一个与最后三个中的一个进行了切换。当我这样做时,以前失败的图像的问题消失了,而被推到列表末尾的图像开始失败。
所以我想我可以从上面推断出,当超过25个HEAD请求快速连续发生时,后续的HEAD请求将失败,而不管具体的URL是什么。我还知道问题出在IIS服务器上,而不是远程图像托管服务器上,因为Wireshark跟踪中缺少超过前25个的请求。
我用来执行HEAD请求的代码片段如下所示。有人能给予我一些建议吗?我尝试了请求头值的各种不同组合,但似乎没有任何区别。我的直觉是,在某个地方有一些IIS设置,限制并发HttpWebRequest的数量为25在任何一个请求到ASP.NET页面。
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;
}
1条答案
按热度按时间wkyowqbh1#
我自己已经解决了这个问题,问题确实是允许的连接数,默认设置为24。
在我的示例中,我将仅在
MyHttpWebRequest.ServicePoint.CurrentConnections
小于10时执行映像检查。要增加最大限制,只需将
ServicePointManager.DefaultConnectionLimit
设置为所需的并发连接数。另一种可能对某些人有帮助的方法是减少空闲时间,即连接等待直到它自己销毁的时间。要改变这一点,你需要将
MyHttpWebRequest.ServicePoint.MaxIdleTime
设置为以毫秒为单位的超时值。