HTTPS 上的 HttpWebRequest 的随机问题
我们有一个应用程序,使用 HttpWebRequest 通过 HTTPS 将数据发布到远程服务器(由 apache 前端处理)。
大多数时候,一切都很好。
有时,我们会遇到以下异常:
WebException occured SecureChannelFailure ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
at System.Net.HttpWebRequest.GetRequestStream()
但是这个异常被捕获,应用程序稍后重试,一切都会再次正常(HTTPS 握手中一定会出现某些问题,我不知道是什么)。
最近,我们遇到了一个无法重现的新问题:
在网站端(apache),我们有一个 HTTP 403,并显示消息“重新协商握手失败:客户端不接受!?”。
在 .NET 客户端,我们发生了静默崩溃(或者应用程序在没有超时的情况下卡住了,我无法判断)。我们唯一知道的是:这不是应用程序正确处理的 WebException。 不幸的是,这部分代码没有足够的异常日志记录,并且我们无法轻松部署具有 System.Net 跟踪的应用程序的新版本以围绕握手进行调查。
有人知道可能是什么问题吗?
这是代码:
HttpWebRequest req = WebRequest.Create(new Uri(url)) as HttpWebRequest;
// set client certificate and server certificate validation callback
ConfigureWebRequestSecurity(req);
req.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");
req.AutomaticDecompression = DecompressionMethods.GZip;
req.Method = "POST";
req.ContentType = "text/xml";
req.ContentLength = data.Length;
HttpWebResponse resp = null;
try
{
using (Stream post = req.GetRequestStream())
{
post.Write(data, 0, data.Length);
}
resp = req.GetResponse() as HttpWebResponse;
Log.Logger.DebugFormat("REST : HTTP Response={0}({1})", (int)resp.StatusCode, resp.StatusCode.ToString());
if (!resp.StatusCode.Equals(HttpStatusCode.OK))
{
throw new MOServerErrorException("The server did not respond with status 200 (OK), but with " + resp.StatusCode);
}
}
catch (WebException e)
{
string m = string.Format("REST : WebException occured {0}", e.Status.ToString());
throw new MOServerErrorException(m, e);
}
finally
{
if (resp != null)
resp.Close();
}
编辑: 好的,我已经成功重现了该问题。线程挂在 GetRequestStream() 中。 这是堆栈:
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x2f bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x25 bytes
> System.dll!System.Net.LazyAsyncResult.WaitForCompletion(bool snap) + 0xd3 bytes
System.dll!System.Net.Security.SslState.CheckEnqueueRead(byte[] buffer = {byte[4096]}, int offset = 0, int count = 4096, System.Net.AsyncProtocolRequest request) + 0x194 bytes
System.dll!System.Net.Security._SslStream.StartReading(byte[] buffer = {byte[4096]}, int offset = 0, int count = 4096, System.Net.AsyncProtocolRequest asyncRequest = null) + 0x6d bytes
System.dll!System.Net.Security._SslStream.ProcessRead(byte[] buffer, int offset, int count, System.Net.AsyncProtocolRequest asyncRequest = null) + 0x6b bytes
System.dll!System.Net.TlsStream.Read(byte[] buffer, int offset, int size) + 0x58 bytes
System.dll!System.Net.PooledStream.Read(byte[] buffer, int offset, int size) + 0x1b bytes
System.dll!System.Net.Connection.SyncRead(System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}, bool userRetrievedStream = false, bool probeRead = true) + 0x12a bytes
System.dll!System.Net.Connection.PollAndRead(System.Net.HttpWebRequest request, bool userRetrievedStream) + 0x5a bytes
System.dll!System.Net.ConnectStream.PollAndRead(bool userRetrievedStream) + 0x1b bytes
System.dll!System.Net.HttpWebRequest.EndWriteHeaders(bool async) + 0xa2 bytes
System.dll!System.Net.HttpWebRequest.WriteHeadersCallback(System.Net.WebExceptionStatus errorStatus, System.Net.ConnectStream stream = {System.Net.ConnectStream}, bool async) + 0x16 bytes
System.dll!System.Net.ConnectStream.WriteHeaders(bool async) + 0x2d1 bytes
System.dll!System.Net.HttpWebRequest.EndSubmitRequest() + 0x82 bytes
System.dll!System.Net.HttpWebRequest.SetRequestSubmitDone(System.Net.ConnectStream submitStream) + 0xf7 bytes
System.dll!System.Net.Connection.CompleteConnection(bool async, System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}) + 0x158 bytes
System.dll!System.Net.Connection.CompleteStartConnection(bool async, System.Net.HttpWebRequest httpWebRequest) + 0x177 bytes
System.dll!System.Net.Connection.CompleteStartRequest(bool onSubmitThread, System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}, System.Net.TriState needReConnect = True) + 0x9a bytes
System.dll!System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}) + 0x293 bytes
System.dll!System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}, string connName = "S>1054081937") + 0x7c bytes
System.dll!System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint servicePoint) + 0xf9 bytes
System.dll!System.Net.HttpWebRequest.GetRequestStream(out System.Net.TransportContext context = null) + 0x1d3 bytes
System.dll!System.Net.HttpWebRequest.GetRequestStream() + 0xe bytes
它挂在这里,没有发生超时。听起来像是网络堆栈中的错误!
We have an application using HttpWebRequest to post data to a remote server, over HTTPS (handled by an apache front-end).
Most of time, everything works fine.
From time to time, we have the following exception :
WebException occured SecureChannelFailure ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
at System.Net.HttpWebRequest.GetRequestStream()
But this exception is caught, the application retries a bit later, and everything goes fine again (something must fail in the HTTPS handshake, I don't know what).
Recently, we had a new problem we can't reproduce :
On the web-site side (apache), we have a HTTP 403, with message " Re-negotiation handshake failed: Not accepted by client!? ".
On the .NET client-side, we have a silent crash (or application is stuck without timeout, I can't tell). The only thing we know : it's not a WebException which is correctly handled by the application.
Unfortunately, there's not enough Exception logging around this portion of code, and we cannot easily deploy a new version of the application with System.Net traces for investigation around handshake.
Does anyone have an idea of what could be the problem ?
Here is the code :
HttpWebRequest req = WebRequest.Create(new Uri(url)) as HttpWebRequest;
// set client certificate and server certificate validation callback
ConfigureWebRequestSecurity(req);
req.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");
req.AutomaticDecompression = DecompressionMethods.GZip;
req.Method = "POST";
req.ContentType = "text/xml";
req.ContentLength = data.Length;
HttpWebResponse resp = null;
try
{
using (Stream post = req.GetRequestStream())
{
post.Write(data, 0, data.Length);
}
resp = req.GetResponse() as HttpWebResponse;
Log.Logger.DebugFormat("REST : HTTP Response={0}({1})", (int)resp.StatusCode, resp.StatusCode.ToString());
if (!resp.StatusCode.Equals(HttpStatusCode.OK))
{
throw new MOServerErrorException("The server did not respond with status 200 (OK), but with " + resp.StatusCode);
}
}
catch (WebException e)
{
string m = string.Format("REST : WebException occured {0}", e.Status.ToString());
throw new MOServerErrorException(m, e);
}
finally
{
if (resp != null)
resp.Close();
}
EDIT :
Ok, I've managed to reproduce the problem. The thread hangs in GetRequestStream().
Here is the stack :
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x2f bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x25 bytes
> System.dll!System.Net.LazyAsyncResult.WaitForCompletion(bool snap) + 0xd3 bytes
System.dll!System.Net.Security.SslState.CheckEnqueueRead(byte[] buffer = {byte[4096]}, int offset = 0, int count = 4096, System.Net.AsyncProtocolRequest request) + 0x194 bytes
System.dll!System.Net.Security._SslStream.StartReading(byte[] buffer = {byte[4096]}, int offset = 0, int count = 4096, System.Net.AsyncProtocolRequest asyncRequest = null) + 0x6d bytes
System.dll!System.Net.Security._SslStream.ProcessRead(byte[] buffer, int offset, int count, System.Net.AsyncProtocolRequest asyncRequest = null) + 0x6b bytes
System.dll!System.Net.TlsStream.Read(byte[] buffer, int offset, int size) + 0x58 bytes
System.dll!System.Net.PooledStream.Read(byte[] buffer, int offset, int size) + 0x1b bytes
System.dll!System.Net.Connection.SyncRead(System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}, bool userRetrievedStream = false, bool probeRead = true) + 0x12a bytes
System.dll!System.Net.Connection.PollAndRead(System.Net.HttpWebRequest request, bool userRetrievedStream) + 0x5a bytes
System.dll!System.Net.ConnectStream.PollAndRead(bool userRetrievedStream) + 0x1b bytes
System.dll!System.Net.HttpWebRequest.EndWriteHeaders(bool async) + 0xa2 bytes
System.dll!System.Net.HttpWebRequest.WriteHeadersCallback(System.Net.WebExceptionStatus errorStatus, System.Net.ConnectStream stream = {System.Net.ConnectStream}, bool async) + 0x16 bytes
System.dll!System.Net.ConnectStream.WriteHeaders(bool async) + 0x2d1 bytes
System.dll!System.Net.HttpWebRequest.EndSubmitRequest() + 0x82 bytes
System.dll!System.Net.HttpWebRequest.SetRequestSubmitDone(System.Net.ConnectStream submitStream) + 0xf7 bytes
System.dll!System.Net.Connection.CompleteConnection(bool async, System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}) + 0x158 bytes
System.dll!System.Net.Connection.CompleteStartConnection(bool async, System.Net.HttpWebRequest httpWebRequest) + 0x177 bytes
System.dll!System.Net.Connection.CompleteStartRequest(bool onSubmitThread, System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}, System.Net.TriState needReConnect = True) + 0x9a bytes
System.dll!System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}) + 0x293 bytes
System.dll!System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest request = {System.Net.HttpWebRequest}, string connName = "S>1054081937") + 0x7c bytes
System.dll!System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint servicePoint) + 0xf9 bytes
System.dll!System.Net.HttpWebRequest.GetRequestStream(out System.Net.TransportContext context = null) + 0x1d3 bytes
System.dll!System.Net.HttpWebRequest.GetRequestStream() + 0xe bytes
It hangs here, no timeout occurs. Sounds like a bug in the network stack !!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
似乎是 KB980817
我没有设法安装建议的修补程序(安装一切顺利...但 System.dll 保持不变)。
作为解决方法,我使用 API 的异步版本(开始...结束)并自行管理超时。
Appears to be KB980817
I didn't manage to install the proposed hotfix (setup goes fine... but System.dll remains unchanged).
As a workaround, I'm using the async version of the API (Begin ...End) and manage a timeout by myself.