System.Net.HttpWebRequest выдает различные webExceptionStatus для SSL-запросов и запросов, отличных от SSL, при особых условиях
Эта статья поможет вам устранить проблему, из-за которой при использовании класса возникает другое WebExceptionStatus
System.Net.HttpWebRequest
.
Исходная версия продукта: .NET Framework
Исходный номер базы знаний: 2007873
Симптомы
Класс Microsoft .Net Framework используется System.Net.HttpWebRequest
для отправки http- или HTTPS-запроса на сервер. Этот запрос занимает некоторое время, чтобы получить ответ от сервера. В течение этого времени ожидания, если время системных часов увеличивается вручную или системные часы отстают, а затем служба времени Windows адаптируется к фактическому местному времени, вы можете столкнуться с одним из следующих сценариев:
Для запроса, который был отправлен по протоколу HTTP в виде открытого System.Net.HttpWebRequest
текста, класс вызовет следующее исключение:
Запрос прерван: истекло время ожидания операции.
Кроме того, Status
свойство в вызываемом WebException
объекте будет указывать значение WebExceptionStatus.Timeout
.
Для запроса, который был отправлен по протоколу System.Net.HttpWebRequest
HTTPS, класс вызовет одно из следующих исключений:
Базовое подключение было закрыто: произошла непредвиденная ошибка при получении.
Кроме того, Status
свойство в вызываемом WebException
объекте будет указывать значение WebExceptionStatus.ReceiveFailure
.
Или
Базовое подключение было закрыто. Сервер закрыл подключение, которое должно было оставаться активным.
Кроме того, Status
свойство в вызываемом WebException
объекте будет указывать значение WebExceptionStatus.KeepAliveFailure
.
Во всех описанных выше сценариях объект , который перехватил, имеет InnerException
свойство . При перехвате WebException
и ссылке на WebException.InnerException.InnerException
свойство вы заметите, что во всех приведенных выше случаях Message
строка будет указывать:
Произошел сбой при попытке подключения, поскольку истекло время ожидания ответа от подключаемой стороны, либо произошел сбой уже установленного подключения, поскольку подключенный узел не ответил.
Это сообщение является подробной интерпретацией кода ошибки Winsock 10060 = WSAETIMEDOUT.
Поэтому при увеличении системного времени вручную Winsock правильно выдает ошибку времени ожидания 10060, но она упаковывается в виде различных типов исключений для ssl-запросов и запросов, отличных от SSL.
При обычных обстоятельствах ожидания, когда системное время не подделывается, сценарии SSL и не ssl правильно отражают WebExceptionStatus.Timeout
состояние и выдают распространенное исключение: истекло время ожидания операции.
Причина
При выполнении запроса по протоколу SSL или по протоколу System.Net.ServicePointManager
, отличному от SSL, класс назначит запрос внутреннему подключению, которое в конечном итоге создаст подключение Winsock. В случае SSL-запросов этот запрос или подключение проходит через другой внутренний класс SSL/TLS, который отвечает за шифрование или расшифровку данных. Для подключений, отличных от SSL, этот внутренний класс SSL/TLS не используется вообще.
При изменении времени и обнаружении исключения на уровне Winsock эта ошибка теперь должна перемещаться вверх от Winsock до уровня приложения. Для подключений, отличных от SSL, это исключение перехватывалось непосредственно внутренним классом подключения, но для SSL-запросов эта ошибка обрабатывается внутренним классом SSL/TLS. Этот класс рассматривает эту ошибку, не связанную ReceiveFailure
с SSL, как или KeepAliveFailure
и, следовательно, имеет другое состояние исключения, в то время как при подключении, отличном от SSL, ошибка приводится правильно, так как она обрабатывается другим классом.
Статус
Такое поведение является особенностью данного продукта.
Решение
Чтобы устранить это несоответствие типов создаваемых исключений при этом специальном условии, когда системное время подделывается, приложению необходимо перехватывать WebException
и ссылаться на WebException.InnerException.InnerException.Message
свойство .
Message
Если строка равна подробной ошибке winsock, эквивалентной 10060 = WSAETIMEDOUT, можно рассматривать ReceiveFailure
или KeepAliveFailure
как обычный тайм-аут и не рассматривать его как ReceiveFailure
или KeepAliveFailure
.
Приложение может использовать приведенный ниже обходной путь при выполнении catch()
WebException
для английской версии платформы. Для локализованной версии платформы необходимо изменить приведенное ниже решение в зависимости от локализации языка.
Важно!
Этот пример кода предоставляется как есть и предназначен только для демонстрационных целей. Он предоставляется без гарантий и не предоставляет никаких прав.
try
{
......
}
catch (WebException oWEx)
{
WebExceptionStatus oStatus = oWEx.Status;
String strTimeoutErrorMessage = "A connection attempt failed because the connected party did not properly respond "
+ "after a period of time, or established connection failed because connected host has failed to respond";
switch (oStatus)
{
case WebExceptionStatus.KeepAliveFailure:
if ((oWEx.InnerException != null) && (oWEx.InnerException.InnerException != null)
&& oWEx.InnerException.InnerException.Message.ToString().Equals(strTimeoutErrorMessage, StringComparison.CurrentCultureIgnoreCase))
{ //----------------------------------------------------------------------
// This is Timeout Error which is wrongly thrown as a ReceiveFailure for
// SSL requests under this special condition.
//
// Handle this as a Timeout Error
//----------------------------------------------------------------------
}
else
{
//----------------------------------------------------------------------
// This is truly a KeepAliveFailure.
//----------------------------------------------------------------------
}
break;
case WebExceptionStatus.Timeout:
//----------------------------------------------------------------------
// This is a Timeout.
//----------------------------------------------------------------------
break;
case WebExceptionStatus.ReceiveFailure:
if ((oWEx.InnerException != null)
&& (oWEx.InnerException.InnerException != null)
&& oWEx.InnerException.InnerException.Message.ToString ().Equals (strTimeoutErrorMessage, StringComparison.CurrentCultureIgnoreCase))
{ //----------------------------------------------------------------------
// This is Timeout Error which is wrongly thrown as a ReceiveFailure for
// SSL requests under this special condition.
//
// Handle this as a Timeout Error
//----------------------------------------------------------------------
}
else
{ //----------------------------------------------------------------------
// This is truly a ReceiveFailure.
//----------------------------------------------------------------------
}
break;
default:
//----------------------------------------------------------------------
// This is some other Exception
//----------------------------------------------------------------------
break;
}
}
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по