如果 Thread.CurrentThread.CurrentCulture 更改,HttpWebRequest 会超时
如果将 Thread.CurrentThread.CurrentCulture 更改为与已安装的(操作系统区域性)不同的内容,则对 HttpWebRequest.GetResponse() 的调用将始终超时。
为了澄清起见,这里是我的实用程序类的内容,它正在做肮脏的工作:
private static void ReplicateCookies(HttpWebRequest request)
{
if (HttpContext.Current == null)
return;
if (request.CookieContainer == null)
request.CookieContainer = new CookieContainer();
foreach (var cookie in from object key in HttpContext.Current.Request.Cookies.Keys select HttpContext.Current.Request.Cookies[key.ToString()])
request.CookieContainer.Add(new Cookie(cookie.Name, cookie.Value, cookie.Path, string.IsNullOrEmpty(cookie.Domain)
? HttpContext.Current.Request.Url.Host
: cookie.Domain));
}
private HttpWebRequest CreateRequest(string url, string method = null)
{
var httpRequest = WebRequest.Create(url) as HttpWebRequest;
ReplicateCookies(httpRequest);
httpRequest.KeepAlive = false;
httpRequest.Method = method ?? "GET";
httpRequest.Timeout = 20000;
httpRequest.Proxy = null;
httpRequest.ServicePoint.ConnectionLeaseTimeout = 20000;
httpRequest.ServicePoint.MaxIdleTime = 10000;
return httpRequest;
}
public string ReadWebPage(string url)
{
var oldCulture = Thread.CurrentThread.CurrentCulture.Name;
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
string result;
var httpRequest = CreateRequest(url);
httpRequest.Headers.Add("Accept-Language", oldCulture);
try
{
using (var httpResponse = httpRequest.GetResponse())
{
using (var stream = httpResponse.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
result = reader.ReadToEnd();
reader.Close();
}
stream.Flush();
stream.Close();
}
httpResponse.Close();
}
}
finally
{
httpRequest.Abort();
}
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(oldCulture);
return result;
}
如果您想知道:
- 在 ReplicateCookies 中,如果您使用 null 作为域调用 CookieCOntainer.Add ,它在运行时会失败,
- 代码已经包含了一个修复程序当前文化问题。继续,取出所有正在改变文化的代码,将线程文化设置为某种内容(例如“fr-FR”)并尝试一下代码。
我已经确保:
- 没有代理干扰请求
- 没有防火墙设置阻止这样的请求
也许值得一提的是,这在 MVC3 Web 应用程序内部用于生成模板化消息 - 其中模板本身就是网页。该应用程序将其文化设置如下(Global.asax.cs):
protected void Application_AcquireRequestState()
{
if (HttpContext.Current == null)
return;
if (HttpContext.Current.Session == null)
return;
if (HttpContext.Current.Session["Culture"] != null)
CultureHelper.SetCulture(HttpContext.Current.Session["Culture"].ToString());
}
出于某种原因,辅助类:
public static class CultureHelper
{
public static void SetCulture(string culture)
{
if (string.IsNullOrEmpty(culture))
return;
var cultureInfo = new CultureInfo(culture);
if (culture.ToLower().Equals("fr-fr") || culture.ToLower().Equals("fr"))
cultureInfo.NumberFormat.NumberGroupSeparator = cultureInfo.NumberFormat.CurrencyGroupSeparator = ".";
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
}
French 默认使用空格作为千位分隔符 - 因此是 if 语句。
ReplicateCookies 方法会将会话 cookie 和身份验证 cookie 复制到内部请求,以便在生成的内部请求中保留会话/身份验证。
该网站显然有办法改变当前的文化(改变会话值)。在修复 ReadWebPage 方法之前,一切都会正常工作,直到文化发生改变。之后,每个 HttpWebRequest.GetResponse 都会超时,直到区域性改回(在我的例子中)en-GB。
有什么想法为什么会发生这种情况吗?我可能在某个地方做了一些严重错误的事情。正如我所说,它在当前状态下工作。只是不太漂亮。
If you change Thread.CurrentThread.CurrentCulture to something different than installed (OS culture), the call to HttpWebRequest.GetResponse() will always time out.
Just for clarification, here's contents of my utility class that is doing the dirty work:
private static void ReplicateCookies(HttpWebRequest request)
{
if (HttpContext.Current == null)
return;
if (request.CookieContainer == null)
request.CookieContainer = new CookieContainer();
foreach (var cookie in from object key in HttpContext.Current.Request.Cookies.Keys select HttpContext.Current.Request.Cookies[key.ToString()])
request.CookieContainer.Add(new Cookie(cookie.Name, cookie.Value, cookie.Path, string.IsNullOrEmpty(cookie.Domain)
? HttpContext.Current.Request.Url.Host
: cookie.Domain));
}
private HttpWebRequest CreateRequest(string url, string method = null)
{
var httpRequest = WebRequest.Create(url) as HttpWebRequest;
ReplicateCookies(httpRequest);
httpRequest.KeepAlive = false;
httpRequest.Method = method ?? "GET";
httpRequest.Timeout = 20000;
httpRequest.Proxy = null;
httpRequest.ServicePoint.ConnectionLeaseTimeout = 20000;
httpRequest.ServicePoint.MaxIdleTime = 10000;
return httpRequest;
}
public string ReadWebPage(string url)
{
var oldCulture = Thread.CurrentThread.CurrentCulture.Name;
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
string result;
var httpRequest = CreateRequest(url);
httpRequest.Headers.Add("Accept-Language", oldCulture);
try
{
using (var httpResponse = httpRequest.GetResponse())
{
using (var stream = httpResponse.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
result = reader.ReadToEnd();
reader.Close();
}
stream.Flush();
stream.Close();
}
httpResponse.Close();
}
}
finally
{
httpRequest.Abort();
}
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo(oldCulture);
return result;
}
In case you're wondering:
- in ReplicateCookies, if you call CookieCOntainer.Add with null as domain it fails in runtime
- the code already contains a fix that gets around the CurrentCulture issue. Go on, take out all the code that is changing the culture, set your thread culture to something (for example "fr-FR") and give the code a spin.
I've made sure that:
- no proxy is interfering with request
- no firewall settings prevent requests like this
Perhaps it's worth mentioning that this was used inside a MVC3 web application internally to generate templated messages - where a template is a web page itself. The application sets it's culture like this (Global.asax.cs):
protected void Application_AcquireRequestState()
{
if (HttpContext.Current == null)
return;
if (HttpContext.Current.Session == null)
return;
if (HttpContext.Current.Session["Culture"] != null)
CultureHelper.SetCulture(HttpContext.Current.Session["Culture"].ToString());
}
And the helper class:
public static class CultureHelper
{
public static void SetCulture(string culture)
{
if (string.IsNullOrEmpty(culture))
return;
var cultureInfo = new CultureInfo(culture);
if (culture.ToLower().Equals("fr-fr") || culture.ToLower().Equals("fr"))
cultureInfo.NumberFormat.NumberGroupSeparator = cultureInfo.NumberFormat.CurrencyGroupSeparator = ".";
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
}
French by default uses space as thousands delimiter for some reason - thus the if statement.
The ReplicateCookies method will copy session cookie and authentication cookie to the internal request so the session / authentication is preserved in resulting internal request.
The site obviously has means to change the current culture (change session value). Prior to the fix in ReadWebPage method everything would work fine until culture was changed. After that every HttpWebRequest.GetResponse would time out until culture was changed back to - in my case - en-GB.
Any ideas why this is happening? I could be doing something grossly wrong somewhere. As I said it's working in it's current state. It's just not very pretty.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于在任何人看到该帖子之前快速删除该帖子的所有尝试都失败了,因此解决方案如下。和往常一样,这是你从未想到的一件事——会议。当我画“在这里砸碎你的头!”时一张纸上的黑点,这是更正的代码:
说明:问题出在 ReplicateCookies 方法中。其中最重要的是重写 ASP 会话 cookie。由于它正在调用同一进程,因此后来挂起(并最终超时),因为初始请求的会话被锁定 - 并且传入请求试图使用同一会话。
现在把这个大黑点的头部磁铁挂在墙上......
Since all attempts to quickly delete this post before anyone sees it failed, here's the solution. As usual it was that one thing you never think of - session. While I draw the "Smash your head here!" black dot on a piece of paper, here's the corrected code:
Explanation: the issue was in ReplicateCookies method. Among everything else it was rewriting the ASP session cookie. And since it was making a call to the same process the later hang (and eventually timed out) because the session from initial request was locked - and the incoming request was trying to use the same session.
Now off to hang this big black dot of a head magnet on the wall ...