Когда веб-сервер отвечает на HttpWebRequest.GetResponse()
с HTTP 304 (Not Modified), GetResponse()
дает WebException
, что для меня очень странно. Является ли это по дизайну или я пропущу что-то очевидное здесь?HttpWebRequest.GetResponse throws WebException по HTTP 304
ответ
Хорошо, это похоже на поведенческое поведение и прекрасный пример vexing exception. Это может быть решена с этим:
public static HttpWebResponse GetHttpResponse(this HttpWebRequest request)
{
try
{
return (HttpWebResponse) request.GetResponse();
}
catch (WebException ex)
{
if(ex.Response == null || ex.Status != WebExceptionStatus.ProtocolError)
throw;
return (HttpWebResponse)ex.Response;
}
}
Это действительно расстраивает проблема, и в качестве альтернативы можно обойти, используя следующий класс метод расширения и вызова request.BetterGetResponse()
//-----------------------------------------------------------------------
//
// Copyright (c) 2011 Garrett Serack. All rights reserved.
//
//
// The software is licensed under the Apache 2.0 License (the "License")
// You may not use the software except in compliance with the License.
//
//-----------------------------------------------------------------------
namespace CoApp.Toolkit.Extensions {
using System;
using System.Net;
public static class WebRequestExtensions {
public static WebResponse BetterEndGetResponse(this WebRequest request, IAsyncResult asyncResult) {
try {
return request.EndGetResponse(asyncResult);
}
catch (WebException wex) {
if(wex.Response != null) {
return wex.Response;
}
throw;
}
}
public static WebResponse BetterGetResponse(this WebRequest request) {
try {
return request.GetResponse();
}
catch (WebException wex) {
if(wex.Response != null) {
return wex.Response;
}
throw;
}
}
}
}
Вы читать больше об этом в своем блоге на эту тему в http://fearthecowboy.com/2011/09/02/fixing-webrequests-desire-to-throw-exceptions-instead-of-returning-status/
Способ избежать этого System.WebException
это установить AllowAutoRedirect свойство false
. Это отключает логику автоматического перенаправления WebRequest
. Кажется, что он был нарушен для 304 запросов перенаправления, поскольку он не является реальным перенаправлением в строгом смысле. Конечно, это означает, что другие запросы перенаправления 3xx
должны обрабатываться вручную.
Абсолютно блестящий. Почему я должен платить за тяжелое оборудование для исключения, если оно мне не нужно? – jsuddsjr
я наткнулся на этот вопрос с кодом:
try
{
...
var webResponse = req.GetResponse();
...
}
catch (WebException ex)
{
Log.Error("Unknown error occured", ex);
//throw;
}
И кажется, что если удаленный сервер возвращает 304 статуса он должен быть передан в браузер, бросая эту ошибку или возвращения пользовательских 304, так что браузер может вернуться кешированный ответ. В противном случае вы, вероятно, получите пустой ответ от удаленного сервера.
Так что в моем случае для нормального поведения с правильной обработкой кэша должны быть как:
try
{
...
var webResponse = req.GetResponse();
...
}
catch (WebException ex)
{
if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotModified)
throw;
Log.Error("Unknown error occured", ex);
}
Подобно тому, как FYI, это обновление Anton Gogolev's answer, который использует (VS2015) when
положения на C# 6. Это немного менее раздражает при использовании отладчика, поскольку он удаляет одну точку останова:
public static HttpWebResponse GetHttpResponse(this HttpWebRequest request)
{
try
{
return (HttpWebResponse) request.GetResponse();
}
catch (WebException ex)
when (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null)
{
return (HttpWebResponse) ex.Response;
}
}
Это работает в большинстве случаев, но некоторые веб-серверы могут вернуть тело ответа при возврате ошибки 404. В этом случае код выше будет обрабатывать 404, поскольку он обрабатывает 304! – comshak
@comshak это «хорошо знать». Вызывающий код должен знать о допустимых кодах ответа. – roufamatic
Я также добавил '|| ((HttpWebResponse) ex.Response) .StatusCode! = HttpStatusCode.NotModified' –