如何从 403 页面获取图标
How to get the favicon from a 403 page
我正在编写一个允许用户输入 URL 的工具,程序通过尝试显示该网站的图标来响应。我在很多网站上都有这个功能,但给我带来麻烦的一个网站是我的自托管 Trac 网站。似乎 Trac 的正常行为,直到最终用户被授权,是显示一个自定义 403 页面(禁止访问),邀请用户登录。从网络浏览器访问 Trac,favicon 显示在浏览器的选项卡中,即使我我没有登录(并且 Firebug,例如,显示页面内容的 403)。如果我从浏览器查看源代码,favicon 的位置就在源代码中。但是,在我的应用程序中,使用 request.GetResponse()
请求 Trac 网站会抛出一个包含 403 的 WebException
,让我没有机会读取包含查找图标所需的重要信息的响应流。
我已经有了下载网站 HTML 并提取其网站图标位置的代码。我坚持的是下载网站的 HTML,即使它以 403 响应。
我尝试了 HttpWebRequest
对象的各种 UserAgent
、Accept
和 AcceptLanguage
属性,但没有帮助。当我在某处读到 .NET 做得不好时,我也尝试自己进行任何重定向。仍然没有运气。
这是我拥有的:
public static MemoryStream DownloadHtml(
string urlParam,
int timeoutMs = DefaultHttpRequestTimeoutMs,
string userAgent = "",
bool silent = false
)
{
MemoryStream result = null;
HttpWebRequest request = null;
HttpWebResponse response = null;
try
{
Func<string, HttpWebRequest> createRequest = (urlForFunc) =>
{
var requestForAction = (HttpWebRequest)HttpWebRequest.Create(urlForFunc);
// This step is now required by Wikipedia (and others?) to prevent periodic or
// even constant 403's (Forbidden).
requestForAction.UserAgent = userAgent;
requestForAction.Accept = "text/html";
requestForAction.AllowAutoRedirect = false;
requestForAction.Timeout = timeoutMs;
return requestForAction;
};
string urlFromResponse = "";
string urlForRequest = "";
do
{
if(response == null)
{
urlForRequest = urlParam;
}
else
{
urlForRequest = urlFromResponse;
response.Close();
}
request = createRequest(urlForRequest);
response = (HttpWebResponse)request.GetResponse();
urlFromResponse = response.Headers[HttpResponseHeader.Location];
}
while(urlFromResponse != null
&& urlFromResponse.Length > 0
&& urlFromResponse != urlForRequest);
using(var stream = response.GetResponseStream())
{
result = new MemoryStream();
stream.CopyTo(result);
}
}
catch(WebException ex)
{
// Things like 404 and, well, all other web-type exceptions.
Debug.WriteLine(ex.Message);
if(ex.InnerException != null) Debug.WriteLine(ex.InnerException.Message);
}
catch(System.Threading.ThreadAbortException)
{
// Let ac.Thread handle some cleanup.
throw;
}
catch(Exception)
{
if(!silent) throw;
}
finally
{
if(response != null) response.Close();
}
return result;
}
流内容存储在异常对象中。
var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
我正在编写一个允许用户输入 URL 的工具,程序通过尝试显示该网站的图标来响应。我在很多网站上都有这个功能,但给我带来麻烦的一个网站是我的自托管 Trac 网站。似乎 Trac 的正常行为,直到最终用户被授权,是显示一个自定义 403 页面(禁止访问),邀请用户登录。从网络浏览器访问 Trac,favicon 显示在浏览器的选项卡中,即使我我没有登录(并且 Firebug,例如,显示页面内容的 403)。如果我从浏览器查看源代码,favicon 的位置就在源代码中。但是,在我的应用程序中,使用 request.GetResponse()
请求 Trac 网站会抛出一个包含 403 的 WebException
,让我没有机会读取包含查找图标所需的重要信息的响应流。
我已经有了下载网站 HTML 并提取其网站图标位置的代码。我坚持的是下载网站的 HTML,即使它以 403 响应。
我尝试了 HttpWebRequest
对象的各种 UserAgent
、Accept
和 AcceptLanguage
属性,但没有帮助。当我在某处读到 .NET 做得不好时,我也尝试自己进行任何重定向。仍然没有运气。
这是我拥有的:
public static MemoryStream DownloadHtml(
string urlParam,
int timeoutMs = DefaultHttpRequestTimeoutMs,
string userAgent = "",
bool silent = false
)
{
MemoryStream result = null;
HttpWebRequest request = null;
HttpWebResponse response = null;
try
{
Func<string, HttpWebRequest> createRequest = (urlForFunc) =>
{
var requestForAction = (HttpWebRequest)HttpWebRequest.Create(urlForFunc);
// This step is now required by Wikipedia (and others?) to prevent periodic or
// even constant 403's (Forbidden).
requestForAction.UserAgent = userAgent;
requestForAction.Accept = "text/html";
requestForAction.AllowAutoRedirect = false;
requestForAction.Timeout = timeoutMs;
return requestForAction;
};
string urlFromResponse = "";
string urlForRequest = "";
do
{
if(response == null)
{
urlForRequest = urlParam;
}
else
{
urlForRequest = urlFromResponse;
response.Close();
}
request = createRequest(urlForRequest);
response = (HttpWebResponse)request.GetResponse();
urlFromResponse = response.Headers[HttpResponseHeader.Location];
}
while(urlFromResponse != null
&& urlFromResponse.Length > 0
&& urlFromResponse != urlForRequest);
using(var stream = response.GetResponseStream())
{
result = new MemoryStream();
stream.CopyTo(result);
}
}
catch(WebException ex)
{
// Things like 404 and, well, all other web-type exceptions.
Debug.WriteLine(ex.Message);
if(ex.InnerException != null) Debug.WriteLine(ex.InnerException.Message);
}
catch(System.Threading.ThreadAbortException)
{
// Let ac.Thread handle some cleanup.
throw;
}
catch(Exception)
{
if(!silent) throw;
}
finally
{
if(response != null) response.Close();
}
return result;
}
流内容存储在异常对象中。
var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();