如何从webclient获取状态码?
我正在使用WebClient
类将一些数据发布到Web表单。 我想获得表单提交的响应状态代码。 到目前为止,我已经发现如何获取状态码,如果有例外
Catch wex As WebException If TypeOf wex.Response Is HttpWebResponse Then msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode) End If
但是,如果表单提交成功,并没有抛出exception,那么我不会知道状态代码(200,301,302,…)
当没有抛出exception的时候,有什么方法可以获得状态码吗?
PS:我不喜欢使用httpwebrequest / httpwebresponse
试过了。 ResponseHeaders不包含状态码。
如果我没有弄错, WebClient
能够在单个方法调用中抽象出多个不同的请求(例如正确处理100个继续响应,redirect等)。 我怀疑,不使用HttpWebRequest
和HttpWebResponse
,一个独特的状态代码可能不可用。
我觉得如果你对中间状态码不感兴趣,你可以放心地认为最后的状态码是在2xx(成功的)范围内,否则呼叫就不会成功。
状态代码不幸的是在ResponseHeaders
字典中不存在。
您可以检查错误是否为WebException
types,然后检查响应代码;
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.. }
有一种使用reflection的方法。 它适用于.NET 4.0。 它访问一个私人领域,可能无法在其他版本的.NET中工作,无需修改。
我不知道为什么微软不公开这个领域的财产。
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; }
其他方式:
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; } }
Erik的答案在Windows Phone上不起作用。 以下是:
class WebClientEx : WebClient { private WebResponse m_Resp = null; protected override WebResponse GetWebResponse(WebRequest Req, IAsyncResult ar) { return m_Resp = base.GetWebResponse(Req, ar); } public HttpStatusCode StatusCode { get { if (m_Resp != null && m_Resp is HttpWebResponse) return (m_Resp as HttpWebResponse).StatusCode; else return HttpStatusCode.OK; } } }
至less它使用OpenReadAsync
, 对于其他的xxxAsync
方法,强烈build议仔细testing。 框架在代码path的某处调用GetWebResponse; 所有需要做的就是捕获并caching响应对象。
这段代码中的回退代码是200,因为真正的HTTP错误 – 500,404等 – 被报告为例外。 这个技巧的目的是捕获非错误代码,在我的具体情况304(未修改)。 所以后备假设,如果状态代码在某种程度上是不可用的,至less这是一个非错误的。
你应该使用
if (e.Status == WebExceptionStatus.ProtocolError) { HttpWebResponse response = (HttpWebResponse)ex.Response; if (response.StatusCode == HttpStatusCode.NotFound) System.Diagnostics.Debug.WriteLine("Not found!"); }
以防万一别人需要上述黑客的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()
这是我用来扩展WebClientfunction的。 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; } }
因此,您可以通过以下方式发布post并获得结果:
byte[] response = null; using (WebClientCert client = new WebClientCert()) { response = client.UploadValues(postUri, PostFields); HttpStatusCode code = client.StatusCode; string description = client.StatusDescription; //Use this information }
您可以尝试使用此代码从WebException或OpenReadCompletedEventArgs.Error获取HTTP状态码。 它也适用于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; }
您应该可以使用“client.ResponseHeaders [..]”调用,请参阅此链接以获取回应的示例