Záludná chyba při použití HttpWebRequest objektu z Net 2.0
MyEgo.cz
Záludná chyba při použití HttpWebRequest objektu z Net 2.0
Aneb co dělat s 'The server committed a protocol violation. Section=ResponseStatusLine' chybou
Narazil jsem na problém při komunikaci s webovou službou přes http protokol. Co mě ale na chybě zaráželo, že se objevovala jen při opakovaném volání. Při prvním requestu komunikace proběhla v pořádku a odpověď se zpracovala tak jak má. Při druhém zkolabovalo zpracování odpovědi na výše zmíněnou chybu.
Při googlování jsem většinou narazil na to, že se jedná o chybu zpracování hlavičky requestu. Tato chyba se pak řeší pomocí přidáním (tajného, vlastnost není standardně přístupná v kódu) konfiguračního elementu do config souboru. Viz.
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing = "true"/>
</settings>
</system.net>
Avšak řešení mého problému spočívala v jednoduší úpravě. Stačilo nastavit KeepAlive
vlastnost Request objektu na false
. Viz.
private string HttpPost(string postData)
{
HttpWebRequest httpWebRequest = (HttpWebRequest) WebRequest.Create(_serviceUri);
if (_httpTimeOut > 0)
httpWebRequest.Timeout = _httpTimeOut;
if (_proxy != null)
httpWebRequest.Proxy = _proxy;
if (_webserverCredentialName != null)
httpWebRequest.Credentials = _webserverCredentialName;
httpWebRequest.Method = _method;
httpWebRequest.UserAgent = "Test";
httpWebRequest.ContentType = _content;
httpWebRequest.AllowAutoRedirect = false;
httpWebRequest.ContentLength = postData.Length;
httpWebRequest.KeepAlive = false;
using (StreamWriter myWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
myWriter.Write(postData);
}
using (WebResponse response = httpWebRequest.GetResponse())
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
return sr.ReadToEnd();
}
}
}
Falešně jsem se domníval, že když použiji using
konstrukci, tak dojde k úplnému uzavření spojení a nebude potřeba nastavovat KeepAlive parametr. Avšak člověk míní a život mění.
Jediná věc, která mě napadla, proč to nefungovalo původně bez tohoto nastavení je teorie, že k uzavření dojde až po vypršení timeoutu. Takže pokud jsem chtěl opakovat request, tak to padlo při zpracování, protože nebyl uzavřen předchozí request.
Ono hlavně je dobré využívat ještě klauzule try,catch,finally a tradičně ve finally pozavírat vše co je otevřené.
[1] Odchytávání chyb mám jen globálně a při použití USING se případné otevřené spojení uzavře samo. Takže tohle by mělo být ošetřený ;-)
[2] Na to, že using zavírá spojení, není nikdy dobré spoléhat. Ten řádek člověka nezabije a ušetří si tím mnoho problémů. Using je hlavně kvůli tomu, aby volalo Dispose, což ale vůbec nemusí mít nic společného s Close (i když při pohledu na implementaci do zdrojáků .NETu většinou má).