155

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

我对此进行了谷歌搜索,并找到了以下示例

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

这是最好的方法吗?

4

5 回答 5

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

来自评论

您如何格式化 cookie 的名称和值来代替“somecookie”?

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

对于多个 cookie:

wb.Headers.Add(HttpRequestHeader.Cookie, 
              "cookiename1=cookievalue1;" +
              "cookiename2=cookievalue2");
于 2011-10-22T18:30:34.070 回答
69

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

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

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

于 2009-11-22T00:08:33.943 回答
47

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


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);
        }
    }
}
于 2012-07-17T13:45:14.320 回答
15

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;
    }
}
于 2016-04-12T22:53:11.067 回答
6

我认为有一种更简洁的方式,您不必创建新的网络客户端(它也可以与 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;
        }
    }
}

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

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

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

于 2015-05-20T18:58:02.853 回答