我有一个自托管的 WCF 服务,其端点设置为 WebHttpBinding 侦听 HTTP 请求。我需要访问通过这些请求传递的cookie。我可以获得
Cookie:
标头值,但我无法进行实际解析。我的实现尝试是使用 CookieContainer
:
var container = new CookieContainer();
var uri = new Uri("http://localhost/");
container.SetCookies(uri, cookieHeader);
var cookies = container.GetCookies(uri).OfType<Cookie>();
foreach (var cookie in cookies)
{
Console.WriteLine("{0} = {1}", cookie.Name, cookie.Value);
}
此代码的问题是
CookieContainer
希望 cookie 用逗号 (cookieHeader="c1=v1,c2=v2"
) 分隔,而浏览器倾向于使用分号 (cookieHeader="c1=v1;c2=v2"
) 来分隔。由于 RFC 6265 只允许使用分号作为分隔符(不过旧的 RFC 允许两者都使用),我有点困惑为什么 CookieContainer
只支持逗号。现在我正在努力寻找一个替代解决方案来解决这个似乎很典型的问题。如何正确解析cookie? ASP.NET 应该能够做到这一点,它是否公开了任何公开可用的类?
据我了解,
Set-Cookie:
和Cookie:
标题的分隔符有所不同。 如果存在多个标头,则 Set-Cookie:
通常会重复,而 Cookie:
在单个标头中具有多个 cookie。 来自RFC6265:
== Server -> User Agent ==
Set-Cookie: SID=31d4d96e407aad42; Path=/; Secure; HttpOnly
Set-Cookie: lang=en-US; Path=/; Domain=example.com
== User Agent -> Server ==
Cookie: SID=31d4d96e407aad42; lang=en-US
通过附加以逗号分隔的每个标头,可以将
Set-Cookie:
标头 组合 为单个字符串:
Set-Cookie: SID=31d4d96e407aad42; Path=/; Secure; HttpOnly,lang=en-US; Path=/; Domain=example.com
CookieContainer
设计为在客户端(由用户代理)使用,因此 SetCookies(Uri, string)
方法仅解析 Set-Cookie:
使用的语法。
ASP.Net 使用内部方法来解析
Cookie:
标头,并且它似乎没有被任何公共方法公开。 参见HttpListenerRequest.Cookies
:
private CookieCollection ParseCookies(Uri uri, string setCookieHeader) {
GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ParseCookies() uri:" + uri + " setCookieHeader:" + setCookieHeader);
CookieCollection cookies = new CookieCollection();
CookieParser parser = new CookieParser(setCookieHeader);
for (;;) {
Cookie cookie = parser.GetServer();
GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ParseCookies() CookieParser returned cookie:" + ValidationHelper.ToString(cookie));
if (cookie==null) {
// EOF, done.
break;
}
if (cookie.Name.Length==0) {
continue;
}
cookies.InternalAdd(cookie, true);
}
return cookies;
}
Nancy 有一个非常简洁的解析器,如果许可允许,可以使用它:
private IDictionary<string, string> GetCookieData()
{
var cookieDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (!this.Headers.Cookie.Any())
{
return cookieDictionary;
}
var values = this.Headers["cookie"].First().TrimEnd(';').Split(';');
foreach (var parts in values.Select(c => c.Split(new[] { '=' }, 2)))
{
var cookieName = parts[0].Trim();
string cookieValue;
if (parts.Length == 1)
{
//Cookie attribute
cookieValue = string.Empty;
}
else
{
cookieValue = parts[1];
}
cookieDictionary[cookieName] = cookieValue;
}
return cookieDictionary;
}
我正在建立米奇的答案。 有一种方法可以调用 Microsoft 在
System.Net.CookieParser
中提供的 cookie 解析器,该解析器被标记为内部。 System.Net.CookieContainer
是公开的,提供了 SetCookie。
public void SetCookies(Uri uri, string cookieHeader)
所以你可以写一个这样的函数
public static System.Net.CookieContainer ParseCookieHeader(string cookieHeader, System.Uri uri)
{
var cookies = new System.Net.CookieContainer();
cookies.SetCookies(uri: uri,
cookieHeader: cookieHeader);
return cookies;
}
然后要循环遍历所有 cookie,你可以这样做
string cookieHeaderValue = "a=b,c=1";
System.Uri requestUri = new System.Uri("");
var cookies = ParseCookieHeader(cookieHeaderValue, uri: requestUri);
foreach (var cookie in cookies.GetAllCookies())
{
// do something with cookie
}