C# 将 CookieContainer 与 WebClient 类一起使用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1777221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 20:43:18  来源:igfitidea点击:

Using CookieContainer with WebClient class

c#cookieshttpwebrequestwebclientcookiecontainer

提问by Maxim Zaslavsky

I've previously used a CookieContainer with HttpWebRequest and HttpWebResponse sessions, but now, I want to use it with a WebClient. As far as I understand, there is no built-in method like there is for HttpWebRequests (request.CookieContainer). How can I collect cookies from a WebClient in a CookieContainer?

我以前在 HttpWebRequest 和 HttpWebResponse 会话中使用了 CookieContainer,但现在,我想将它与 WebClient 一起使用。据我了解,没有像 HttpWebRequests ( request.CookieContainer)那样的内置方法。如何从 CookieContainer 中的 WebClient 收集 cookie?

I googledfor this and found the following sample:

我用谷歌搜索并找到了以下示例

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

Is this the best way to do it?

这是最好的方法吗?

采纳答案by Justin Grant

Yes. IMHO, overriding GetWebRequest() is the best solution to WebClient's limited functionalty. Before I knew about this option, I wrote lots of really painful code at the HttpWebRequest layer because WebClient almost, but not quite, did what I needed. Derivation is much easier.

是的。恕我直言,覆盖 GetWebRequest() 是 WebClient 功能有限的最佳解决方案。在我知道这个选项之前,我在 HttpWebRequest 层写了很多非常痛苦的代码,因为 WebClient 几乎但不完全是我需要的。推导要容易得多。

Another option is to use the regular WebClient class, but manually populate the Cookie header before making the request and then pull out the Set-Cookies header on the response. There are helper methods on the CookieContainer class which make creating and parsing these headers easier: CookieContainer.SetCookies()and CookieContainer.GetCookieHeader(), respectively.

另一种选择是使用常规 WebClient 类,但在发出请求之前手动填充 Cookie 标头,然后在响应中提取 Set-Cookies 标头。CookieContainer 类上有帮助方法,它们分别使创建和解析这些标头更容易:CookieContainer.SetCookies()CookieContainer.GetCookieHeader()

I prefer the former approach since it's easier for the caller and requires less repetitive code than the second option. Also, the derivation approach works the same way for multiple extensibility scenarios (e.g. cookies, proxies, etc.).

我更喜欢前一种方法,因为它对调用者来说更容易,并且比第二种选择需要的重复代码更少。此外,派生方法对于多个可扩展性场景(例如 cookie、代理等)的工作方式相同。

回答by Rajeesh

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

From Comments

来自评论

How do you format the name and value of the cookie in place of "somecookie" ?

你如何格式化 cookie 的名称和值来代替 "somecookie" ?

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

For multiple cookies:

对于多个 cookie:

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

回答by Pavel Savara

This one is just extension of article you found.

这只是您找到的文章的扩展。


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);
        }
    }
}

回答by dotMorten

I think there's cleaner way where you don't have to create a new webclient (and it'll work with 3rd party libraries as well)

我认为有一种更简洁的方法,您无需创建新的网络客户端(它也可以与 3rd 方库一起使用)

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

Now all you have to do is opt in for which domains you want to use this:

现在您要做的就是选择要使用的域:

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

That means ANY webrequest that goes to example.com will now use your custom webrequest creator, including the standard webclient. This approach means you don't have to touch all you code. You just call the register prefix once and be done with it. You can also register for "http" prefix to opt in for everything everywhere.

这意味着进入 example.com 的任何 webrequest 现在都将使用您的自定义 webrequest 创建者,包括标准 webclient。这种方法意味着您不必接触所有代码。您只需调用一次 register 前缀即可完成。您还可以注册“http”前缀以在任何地方选择加入所有内容。

回答by Ted

The HttpWebRequest modifies the CookieContainer assigned to it. There is no need to process returned cookies. Simply assign your cookie container to every web request.

HttpWebRequest 修改分配给它的 CookieContainer。无需处理返回的 cookie。只需将您的 cookie 容器分配给每个 Web 请求。

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