Я использую класс WebClient
для публикации некоторых данных в веб-форме. Я хотел бы получить код статуса ответа формы. До сих пор я узнал, как получить код состояния, если есть исключение
Catch wex As WebException
If TypeOf wex.Response Is HttpWebResponse Then
msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode)
End If
Однако, если форма отправлена успешно и не выбрано исключение, я не буду знать код состояния (200, 301, 302,...)
Есть ли способ получить код состояния, если нет исключений?
PS: Я предпочитаю не использовать httpwebrequest/httpwebresponse
Пробовал. ResponseHeaders не включают код состояния.
Если я не ошибаюсь, WebClient
способен абстрагировать несколько разных запросов в одном вызове метода (например, правильно обрабатывать 100 ответов, перенаправлений и т.п.). Я подозреваю, что без использования HttpWebRequest
и HttpWebResponse
отдельный код состояния может быть недоступен.
Мне приходит в голову, что если вы не заинтересованы в промежуточных кодах состояния, вы можете спокойно предположить, что окончательный код состояния находится в диапазоне 2xx (успешный), в противном случае вызов не будет успешным.
Код состояния, к сожалению, отсутствует в словаре ResponseHeaders
.
Вы можете проверить, является ли ошибка типа WebException
, а затем проверить код ответа;
if (e.Error.GetType().Name == "WebException")
{
WebException we = (WebException)e.Error;
HttpWebResponse response = (System.Net.HttpWebResponse)we.Response;
if (response.StatusCode==HttpStatusCode.NotFound)
System.Diagnostics.Debug.WriteLine("Not found!");
}
или
try
{
// send request
}
catch (WebException e)
{
// check e.Status as above etc..
}
Если вы используете .Net 4.0 (или меньше):
class BetterWebClient : WebClient
{
private WebRequest _Request = null;
protected override WebRequest GetWebRequest(Uri address)
{
this._Request = base.GetWebRequest(address);
if (this._Request is HttpWebRequest)
{
((HttpWebRequest)this._Request).AllowAutoRedirect = false;
}
return this._Request;
}
public HttpStatusCode StatusCode()
{
HttpStatusCode result;
if (this._Request == null)
{
throw (new InvalidOperationException("Unable to retrieve the status
code, maybe you haven't made a request yet."));
}
HttpWebResponse response = base.GetWebResponse(this._Request)
as HttpWebResponse;
if (response != null)
{
result = response.StatusCode;
}
else
{
throw (new InvalidOperationException("Unable to retrieve the status
code, maybe you haven't made a request yet."));
}
return result;
}
}
Если вы используете .Net 4.5.X или новее, переключитесь на HttpClient:
var response = await client.GetAsync("http://www.contoso.com/");
var statusCode = response.StatusCode;
Есть способ сделать это, используя отражение. Он работает с .NET 4.0. Он обращается к частному полю и может не работать в других версиях .NET без изменений.
Я понятия не имею, почему Microsoft не раскрыла это поле со свойством.
private static int GetStatusCode(WebClient client, out string statusDescription)
{
FieldInfo responseField = client.GetType().GetField("m_WebResponse", BindingFlags.Instance | BindingFlags.NonPublic);
if (responseField != null)
{
HttpWebResponse response = responseField.GetValue(client) as HttpWebResponse;
if (response != null)
{
statusDescription = response.StatusDescription;
return (int)response.StatusCode;
}
}
statusDescription = null;
return 0;
}
Ответ Эрика не работает на Windows Phone как есть. Следующее делает:
class WebClientEx : WebClient
{
private WebResponse m_Resp = null;
protected override WebResponse GetWebResponse(WebRequest Req, IAsyncResult ar)
{
try
{
this.m_Resp = base.GetWebResponse(request);
}
catch (WebException ex)
{
if (this.m_Resp == null)
this.m_Resp = ex.Response;
}
return this.m_Resp;
}
public HttpStatusCode StatusCode
{
get
{
if (m_Resp != null && m_Resp is HttpWebResponse)
return (m_Resp as HttpWebResponse).StatusCode;
else
return HttpStatusCode.OK;
}
}
}
По крайней мере, это происходит при использовании OpenReadAsync
; для других методов xxxAsync
настоятельно рекомендуется тщательное тестирование. Фреймворк вызывает GetWebResponse где-нибудь вдоль пути кода; все, что нужно сделать, это захватить и кэшировать объект ответа.
В этом фрагменте резервный код равен 200, поскольку подлинные ошибки HTTP - 500, 404 и т.д. - в любом случае считаются исключениями. Целью этого трюка является захват кодов без ошибок, в моем конкретном случае 304 (не изменено). Таким образом, запасной вариант предполагает, что если код состояния как-то недоступен, по крайней мере, он не ошибочен.
Вы должны использовать
if (e.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = (HttpWebResponse)ex.Response;
if (response.StatusCode == HttpStatusCode.NotFound)
System.Diagnostics.Debug.WriteLine("Not found!");
}
However if the form is submitted successfully and no exception is thrown...
Это то, что я использую для расширения функциональности WebClient. StatusCode и StatusDescription всегда будут содержать самый последний ответный код/описание.
/// <summary>
/// An expanded web client that allows certificate auth and
/// the retrieval of status' for successful requests
/// </summary>
public class WebClientCert : WebClient
{
private X509Certificate2 _cert;
public WebClientCert(X509Certificate2 cert) : base() { _cert = cert; }
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
if (_cert != null) { request.ClientCertificates.Add(_cert); }
return request;
}
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = null;
response = base.GetWebResponse(request);
HttpWebResponse baseResponse = response as HttpWebResponse;
StatusCode = baseResponse.StatusCode;
StatusDescription = baseResponse.StatusDescription;
return response;
}
/// <summary>
/// The most recent response statusCode
/// </summary>
public HttpStatusCode StatusCode { get; set; }
/// <summary>
/// The most recent response statusDescription
/// </summary>
public string StatusDescription { get; set; }
}
Таким образом, вы можете сделать сообщение и получить результат через:
byte[] response = null;
using (WebClientCert client = new WebClientCert())
{
response = client.UploadValues(postUri, PostFields);
HttpStatusCode code = client.StatusCode;
string description = client.StatusDescription;
//Use this information
}
На всякий случай кому-то еще нужна версия F # описанного выше взлома.
open System
open System.IO
open System.Net
type WebClientEx() =
inherit WebClient ()
[<DefaultValue>] val mutable m_Resp : WebResponse
override x.GetWebResponse (req: WebRequest ) =
x.m_Resp <- base.GetWebResponse(req)
(req :?> HttpWebRequest).AllowAutoRedirect <- false;
x.m_Resp
override x.GetWebResponse (req: WebRequest , ar: IAsyncResult ) =
x.m_Resp <- base.GetWebResponse(req, ar)
(req :?> HttpWebRequest).AllowAutoRedirect <- false;
x.m_Resp
member x.StatusCode with get() : HttpStatusCode =
if not (obj.ReferenceEquals (x.m_Resp, null)) && x.m_Resp.GetType() = typeof<HttpWebResponse> then
(x.m_Resp :?> HttpWebResponse).StatusCode
else
HttpStatusCode.OK
let wc = new WebClientEx()
let st = wc.OpenRead("http://www.stackoverflow.com")
let sr = new StreamReader(st)
let res = sr.ReadToEnd()
wc.StatusCode
sr.Close()
st.Close()
Вы можете использовать вызов "client.ResponseHeaders [..]", см. ссылку для примера возврата материала из ответа
Вы можете попробовать этот код, чтобы получить код состояния HTTP из WebException или из OpenReadCompletedEventArgs.Error. Он также работает в Silverlight, поскольку SL не имеет определения WebExceptionStatus.ProtocolError.
HttpStatusCode GetHttpStatusCode(System.Exception err)
{
if (err is WebException)
{
WebException we = (WebException)err;
if (we.Response is HttpWebResponse)
{
HttpWebResponse response = (HttpWebResponse)we.Response;
return response.StatusCode;
}
}
return 0;
}