WebClient 클래스와 함께 CookieContainer 사용


148

이전에는 HttpWebRequest 및 HttpWebResponse 세션과 함께 CookieContainer를 사용했지만 이제는 WebClient와 함께 사용하고 싶습니다. 내가 이해하는 한 HttpWebRequests ( request.CookieContainer) 와 같은 내장 메소드는 없습니다 . CookieContainer의 WebClient에서 쿠키를 수집하려면 어떻게해야합니까?

내가 이것을 발견 다음 예제를 :

public class CookieAwareWebClient : WebClient
{
    private readonly CookieContainer m_container = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);
        HttpWebRequest webRequest = request as HttpWebRequest;
        if (webRequest != null)
        {
            webRequest.CookieContainer = m_container;
        }
        return request;
    }
}

이것이 최선의 방법입니까?


1
내 관점에서 m_container결코 설정되지 않습니다!? 항상 비어 있지 않습니까?
C4d

HttpWebRequest 클래스는 필요에 따라 내부 필드 CookieContainer를 사용하여 m_container 클래스를 수정한다고 생각합니다.
HeartWare

이것이 당신이 필요한 전부입니다! 응답의 쿠키가 컨테이너에 자동으로 추가됩니다.
lionello

답변:


69

예. IMHO는 GetWebRequest ()를 재정의하는 것이 WebClient의 제한된 기능에 대한 최상의 솔루션입니다. 이 옵션에 대해 알기 전에 HttpWebRequest 레이어에서 WebClient가 거의 고통스럽지 않은 코드를 많이 작성했습니다. 파생이 훨씬 쉽습니다.

또 다른 옵션은 일반 WebClient 클래스를 사용하지만 요청하기 전에 Cookie 헤더를 수동으로 채우고 응답에서 Set-Cookies 헤더를 가져 오는 것입니다. : 만들고 이러한 헤더 쉽게 분석 내린 CookieContainer 클래스의 도우미 방법이 있습니다 CookieContainer.SetCookies()CookieContainer.GetCookieHeader()각각은,.

나는 호출자가 더 쉽고 두 번째 옵션보다 덜 반복적 인 코드를 필요로하기 때문에 전자의 접근 방식을 선호합니다. 또한 파생 접근 방식은 여러 확장 성 시나리오 (예 : 쿠키, 프록시 등)에 대해 동일한 방식으로 작동합니다.


118
 WebClient wb = new WebClient();
 wb.Headers.Add(HttpRequestHeader.Cookie, "somecookie");

댓글에서

"somecookie"대신 쿠키의 이름과 값을 어떻게 포맷합니까?

wb.Headers.Add(HttpRequestHeader.Cookie, "cookiename=cookievalue"); 

여러 쿠키의 경우 :

wb.Headers.Add(HttpRequestHeader.Cookie, 
              "cookiename1=cookievalue1;" +
              "cookiename2=cookievalue2");

"somecookie"대신 쿠키의 이름과 값을 어떻게 포맷합니까?
Neil N

11
@Neil N : wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename = cookievalue"); 여러 쿠키의 경우 : wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename1 = cookievalue1; cookiename2 = cookievalue2");
Ian Kemp

46

이것은 당신이 찾은 기사의 확장 일뿐입니다.


public class WebClientEx : WebClient
{
    public WebClientEx(CookieContainer container)
    {
        this.container = container;
    }

    public CookieContainer CookieContainer
        {
            get { return container; }
            set { container= value; }
        }

    private CookieContainer container = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest r = base.GetWebRequest(address);
        var request = r as HttpWebRequest;
        if (request != null)
        {
            request.CookieContainer = container;
        }
        return r;
    }

    protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
    {
        WebResponse response = base.GetWebResponse(request, result);
        ReadCookies(response);
        return response;
    }

    protected override WebResponse GetWebResponse(WebRequest request)
    {
        WebResponse response = base.GetWebResponse(request);
        ReadCookies(response);
        return response;
    }

    private void ReadCookies(WebResponse r)
    {
        var response = r as HttpWebResponse;
        if (response != null)
        {
            CookieCollection cookies = response.Cookies;
            container.Add(cookies);
        }
    }
}

3
이것은 @Pavel에서 잘 작동했지만 클래스의 기능을 사용하는 방법, 특히 쿠키를 설정하고 가져 오는 방법을 보여 줌으로써이 답변을 향상시킬 수 있습니다.
Corgalore

확장을위한 Thx. 그것을 사용하기 위해 public CookieContainer를 추가합니다. CookieContainer {get {return _container; } set {_container = 값; }}
Igor Shubin

1
@ IgorShubin readonly에서는 container필드 수정자를 제거해야 합니다. 그렇지 않으면 속성에서 설정할 수 없습니다. 코드를 수정했습니다.
hillin

1
Set-Cookie응답 헤더 를 확인하지 ReadCookies않겠습니까?
Achilles

2
당신은 실제로 필요하지 않습니다 GetWebResponseReadCookies쿠키가 자동으로 컨테이너에 추가됩니다 때문에.
lionello

15

HttpWebRequest는 할당 된 CookieContainer를 수정합니다. 반환 된 쿠키를 처리 할 필요가 없습니다. 쿠키 컨테이너를 모든 웹 요청에 할당하기 만하면됩니다.

public class CookieAwareWebClient : WebClient
{
    public CookieContainer CookieContainer { get; set; } = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri uri)
    {
        WebRequest request = base.GetWebRequest(uri);
        if (request is HttpWebRequest)
        {
            (request as HttpWebRequest).CookieContainer = CookieContainer;
        }
        return request;
    }
}

6

새로운 웹 클라이언트를 만들 필요가없는 깔끔한 방법이 있다고 생각합니다 (타사 라이브러리에서도 작동 함)

internal static class MyWebRequestCreator
{
    private static IWebRequestCreate myCreator;

    public static IWebRequestCreate MyHttp
    {
        get
        {
            if (myCreator == null)
            {
                myCreator = new MyHttpRequestCreator();
            }
            return myCreator;
        }
    }

    private class MyHttpRequestCreator : IWebRequestCreate
    {
        public WebRequest Create(Uri uri)
        {
            var req = System.Net.WebRequest.CreateHttp(uri);
            req.CookieContainer = new CookieContainer();
            return req;
        }
    }
}

이제 원하는 도메인을 선택하기 만하면됩니다.

    WebRequest.RegisterPrefix("http://example.com/", MyWebRequestCreator.MyHttp);

즉, example.com으로 이동하는 모든 웹 요청은 이제 표준 웹 클라이언트를 포함하여 사용자 정의 웹 요청 작성자를 사용합니다. 이 접근 방식은 코드를 모두 만질 필요가 없음을 의미합니다. 레지스터 접두사를 한 번만 호출하면됩니다. "http"접두사를 등록하여 모든 곳에서 모든 것을 선택할 수 있습니다.


나는 마지막 두 문장에 대해 확신하지 못한다. 문서는 말 : 는 "의 HttpWebRequest 클래스는 기본적으로 HTTP 및 HTTPS 체계에 대한 서비스 요청에 등록 시도가 실패 이러한 계획에 대해 다른 WebRequest 클래스의 자손을 등록 할 수 있습니다.."
Herohtar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.