【问题标题】:Using CookieContainer with WebClient class将 CookieContainer 与 WebClient 类一起使用
【发布时间】:2010-12-19 03:10:35
【问题描述】:

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

googled为此找到了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;
    }
}

这是最好的方法吗?

【问题讨论】:

  • 从我的角度来看,m_container 永远不会设置!?不是一直都是空的吗?
  • 我相信HttpWebRequest类根据需要使用其内部字段CookieContainer修改了m_container类。
  • 这就是你所需要的!响应中的 cookie 将自动添加到容器中。

标签: c# cookies httpwebrequest webclient cookiecontainer


【解决方案1】:
 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");

【讨论】:

  • 如何格式化cookie的名称和值来代替“somecookie”?
  • @Neil N: wb.Headers.Add(HttpRequestHeader.Cookie, "cookiename=cookievalue");对于多个 cookie: wb.Headers.Add(HttpRequestHeader.Cookie, "cookiename1=cookievalue1; cookiename2=cookievalue2");
  • 这对我来说是最简单的方法,将 cookie 从 Anglesharp 传输到 WebClient 以获得下载链接 :-) 谢谢!
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 这很好@Pavel,虽然你可以通过展示如何使用类的特性来改进这个答案,特别是设置和获取它的cookie。
    • 感谢扩展。为了使用它,我添加了 public CookieContainer CookieContainer { get { return _container; } 设置 { _container = 值; } }
    • @IgorShubin 您必须删除readonly 字段的readonly 修饰符,否则您无法在属性中设置它。我修改了代码。
    • 您不应该检查ReadCookies 中的Set-Cookie 响应标头吗?
    • 您实际上并不需要 GetWebResponseReadCookies,因为 cookie 会自动添加到容器中。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      我认为有一种更简洁的方式,您不必创建新的网络客户端(它也可以与 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”前缀以选择任何地方的所有内容。

      【讨论】:

      • 我不确定最后几句话; docs 说:“HttpWebRequest 类默认注册为 HTTP 和 HTTPS 方案的请求服务。尝试为这些方案注册不同的 WebRequest 后代将失败。”
      猜你喜欢
      • 1970-01-01
      • 2014-06-16
      • 1970-01-01
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多