웹 클라이언트에서 상태 코드를 얻는 방법은 무엇입니까?


90

WebClient클래스를 사용하여 웹 양식에 일부 데이터를 게시하고 있습니다. 양식 제출의 응답 상태 코드를 받고 싶습니다. 지금까지 예외가있는 경우 상태 코드를 얻는 방법을 알아 냈습니다.

Catch wex As WebException
        If TypeOf wex.Response Is HttpWebResponse Then
          msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode)
            End If

그러나 양식이 성공적으로 제출되고 예외가 발생하지 않으면 상태 코드 (200,301,302, ...)를 알 수 없습니다.

예외가 발생하지 않을 때 상태 코드를 얻을 수있는 방법이 있습니까?

추신 : httpwebrequest / httpwebresponse를 사용하지 않는 것을 선호합니다.

답변:


23

그것을 시도했습니다. ResponseHeaders에는 상태 코드가 포함되지 않습니다.

내가 착각하지 않았다면 WebClient은 (는) 단일 메서드 호출에서 여러 개의 개별 요청을 추상화 할 수 있습니다 (예 : 100 개의 Continue 응답, 리디렉션 등을 올바르게 처리). 내가 사용하지 않고 그 의심 HttpWebRequest하고HttpWebResponse , 별개의 상태 코드를 사용하지 못할 수 있습니다.

중간 상태 코드에 관심이 없으면 최종 상태 코드가 2xx (성공) 범위에 있다고 안전하게 가정 할 수 있습니다. 그렇지 않으면 호출이 성공하지 못할 것입니다.

안타깝게도 상태 코드는 ResponseHeaders사전에 없습니다 .


2
유일한 방법은 웹 요청 / 응답 일 것 같습니다
julio

1
다른 200 시리즈 메시지를 명시 적으로 찾고 있다면 문제가있는 것 같습니다 (예 : 201 CREATED- 참조 : w3.org/Protocols/rfc2616/rfc2616-sec10.html ). :-/ "중간"항목을 건너 뛰더라도 명시 적으로 사용할 수 있다면 좋을 것입니다.
Norman H

1
@NormanH, 나는 동의하지 않습니다. WebClient는 상태 코드와 관련하여 약간의 유출 추상화 인 것처럼 보입니다. 건배!
kbrimington 2011

87

오류가 유형인지 확인한 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..
}

WebClient.ResponseHeaders가 아닌 WebException에서 응답 헤더를 얻는 올바른 방법을 알려주는이 답변에 감사드립니다.
Hong

1
네, 가장 좋은 방법은 시도의 catch 블록 및 캐치 WebException이의 응답 데이터를 읽을 실제로
헨릭 하츠

2
여기에 뭔가 빠졌습니다. 나도 'System.Exception'또는 'System.Net.Exception은'오류 '에 대한 정의를 포함하지
그렉 우즈에게

13
호출이 성공하면 예외가 없습니다 (예 : 2xx 또는 3xx 반환). 원래 포스터는 3xx를 찾고 있었고, 나는 204를 찾고, 다른 사람들은 201을 찾고있었습니다. 이것은 질문에 대한 답이 아닙니다.
Simon Brooke

4
원본 포스터가 "예외가 발생하지 않을 때 상태 코드를 얻을 수있는 방법이 있습니까?"라고 썼을 때 지금까지이 답변이 어떻게 찬성되었는지 잘 모르겠습니다. 나는 지금 반대 투표에 아무런 의미가 없다고 생각합니다.
Frog Pr1nce 2015

33

반사를 사용하는 방법이 있습니다. .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;
}

2
FWIW,이 경우에도 반사를 통해 개인 회원에 액세스 할 수 없습니다 윈도우 폰에 수 없습니다
브랜든

BindingFlags에는 "using System.Reflection;"이 필요합니다.
dlchambers

좋지만 SubStatusCode를 얻는 방법이 있습니까? 예를 들어 403.1 또는 403.2?
Roni Tovi

응답 개체에는 SubStatusCode 속성이 있습니다. msdn.microsoft.com/en-us/library/…
Dmitry S.

29

.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;

Windows Phone에서 작동하지 않음-GetWebResponse ()는 두 개의 매개 변수로만 존재합니다. 여전히 +1.
Seva Alekseyev 2013

그것이 작동하지 않는다는 것이 흥미 롭습니다. 귀하의 답변이 트릭을 수행하게되어 기쁩니다!
Erik Philips

저를 위해 일했습니다. 더 높은 답변의 반영은 그렇지 않았습니다 (.NET 4.5 Windows 7 및 10 앱)
David Shields

9

Erik의 대답은 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 (수정되지 않음)에서 오류가 아닌 코드를 캡처하는 것입니다. 따라서 폴백은 상태 코드를 사용할 수없는 경우 적어도 오류가없는 코드라고 가정합니다.


3

당신은 사용해야합니다

if (e.Status == WebExceptionStatus.ProtocolError)
{
   HttpWebResponse response = (HttpWebResponse)ex.Response;             
   if (response.StatusCode == HttpStatusCode.NotFound)
      System.Diagnostics.Debug.WriteLine("Not found!");
}

3
이것은 왜 투표 되었습니까? 영업 이익은 명확하게 진술한다 : However if the form is submitted successfully and no exception is thrown...
케네스 K.에게

2

이것이 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
            }

응답 코드를 찾고 있었기 때문에 이것은 나를 위해 잘 작동했습니다. 좋은 해결책!
evilfish

[HttpClient와 달리] 4xx 및 5xx 응답으로 인해 "response = base.GetWebResponse (request);"에서 WebException이 발생합니다. 선. 예외에서 상태 및 응답을 가져올 수 있습니다 (존재하는 경우).
mwardm

예. 평소처럼 예외를 포착해야합니다. 그러나 예외가 없으면 OP가 원하는 것을 노출합니다.
DFTR

1

다른 사람이 위에서 설명한 해킹의 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()

-1

"client.ResponseHeaders [..]"호출을 사용할 수 있어야합니다. 응답에서 항목을 다시 가져 오는 예제는 이 링크 를 참조하십시오.


1
반환 된 응답 헤더는 server, date, pragma 등과 같은 서버 헤더입니다. 그러나 상태 코드 없음 (200,301,404 ...)
julio

1
죄송합니다. 반환되지 않은 것을 알고 조금 놀랐습니다.
Paul Hadfield

-1

이 코드를 사용하여 WebException 또는 OpenReadCompletedEventArgs.Error에서 HTTP 상태 코드를 가져올 수 있습니다. SL에는 WebExceptionStatus.ProtocolError가 정의되어 있지 않기 때문에 Silverlight에서도 작동합니다.

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.