在 WebClient 类中使用 CookieContainer

我以前在 HttpWebRequest 和 HttpWebResponse 会话中使用过 CookieContainer,但是现在,我想在 WebClient 中使用它。据我所知,没有像 HttpWebRequest (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;
}
}

这是最好的办法吗?

156143 次浏览

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

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

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

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

这只是你找到的文章的延伸。


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

我认为有一种更干净的方式,你不必创建一个新的网络客户端(它也可以与第三方库一起工作)

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 的 web 请求现在都将使用您自定义的 web 请求创建器,包括标准的 webclient。这种方法意味着您不必触及所有代码。您只需调用寄存器前缀一次就可以了。 您也可以注册“ http”前缀,以选择在任何地方的一切。

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