对于 Cookie 的处理上,我最近遇到一个问题,那就是如何分割 Cookie 的内容。有人说是使用逗号分割,有人说是使用分号分割,究竟用哪个才是对的?其实这个答案是需要分为两个过程,分别是请求和响应,来进行回答。请求过程的 Cookie 和响应返回的 Cookie 的格式是不相同的

请求 Request 的 Cookie 是放在 Cookie 头里面的,可以使用逗号或分号进行分割多个不同的 Cookie 内容。 但是大部分情况下都是采用分号加空格 ; 的方式进行分割,而不是逗号分割,且在 Cookie 的 Key 和 Value 里面,是不允许出现分号和逗号字符,如果真需要,那就需要进行转码

根据 rfc2965 可以知道,在 Cookie 里面,服务器端接收的请求是需要处理两个方式分割的内容: 使用分号 ; 分割和使用逗号 , 分割的情况。也就是说采用分号和逗号都是合理的,只是大家遵不遵守这个规范就是另一回事了

Note: For backward compatibility, the separator in the Cookie header

is semi-colon ( everywhere. A server SHOULD also accept comma (,)

as the separator between cookie-values for future compatibility.

为什么会同时支持分号和逗号作为分隔符?这是一个历史原因,再加上,对于请求来说,大部分的请求头,重复加入的时候,是采用逗号进行分割的,而分号分割的是相同的一条信息的多个属性内容。为了能更好的兼容,标准 rfc2965 就规定了 A server SHOULD also accept comma (,) as the separator 服务端应该兼容使用逗号分割的情况。标准里面说的是服务端是 应该 而不是必须,也就是说会存在一些服务端是不支持逗号分割的。我测试了 ASP.NET Core 3.1 和 6.0 的行为,是能支持使用逗号或分号分割的 Cookie 内容

以下是一条通过 Fiddler 工具抓包的请求信息的内容

POST https://test.lindexi.com/api/v1/coursewareShare/link HTTP/1.1
Host: test.lindexi.com
Cookie: x-auth-token=9e712b07dc404fe7b384e7f3dce7bbba; x-auth-app=Demo; x-auth-brand=; client_version=5.2.2.123; client_build_version=95228; client_flags=tabs
X-APM-TraceId: e6d841e5790d43e1a13e6b597281e06b

可以看到以上的请求里多条不同的 Cookie 使用 ; 分号加空格分割,这是比较常用的方法。对于以上的请求的 Cookie 内容,是不能通过 CookieContainer.SetCookies 去解析,原因在于 SetCookies 是设计用来处理响应的 Cookie 而不是用来处理请求的 Cookie 内容,使用 SetCookies 方法只能分割 , 逗号作为分隔符的 Cookie 情况

以上是对于请求的情况,请求是从客户端到服务器端的过程。接下来聊聊从服务器端到客户端的过程:

响应 Response 的 Cookie 是放在 Set-Cookie 头里面,多条 Cookie 一般对应多条 Set-Cookie 头。可以采用 CookieContainer.SetCookies 方法解析,值得一提的是 SetCookies 方法能处理使用 , 逗号分割的多个不同的 Cookie 内容,但是不能处理使用 ; 分号分割的情况。不能处理 ; 分号分割的情况是因为在响应里面,将使用 ; 分号分割 Cookie 的信息,包括分割 Cookie 内容和 Cookie 对应域名和 Cookie 过期时间

如 mozilla 的文档描述:

Set-Cookie: <cookie-name>=<cookie-value>
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<number>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=None; Secure // Multiple attributes are also possible, for example:
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly

以下是一条通过 Fiddler 工具抓包的响应信息的内容

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 24 Aug 2022 01:49:18 GMT
Server: Kestrel
Set-Cookie: Response1=Value; path=/
Set-Cookie: Response2=Value; path=/

可以看到以上的信息是通过多条响应头信息返回的,可以使用如下代码进行解析

    /// <summary>
/// 获取 <see cref="CookieCollection"/> 设置
/// </summary>
/// <param name="httpResponseMessage"></param>
/// <returns></returns>
public static CookieCollection GetCookie(this HttpResponseMessage httpResponseMessage)
{
Uri requestUri = httpResponseMessage.RequestMessage.RequestUri;
var cookieContainer = new CookieContainer();
if (httpResponseMessage.Headers.TryGetValues(HttpKnownHeaderNames.SetCookie, out var cookieValueList))
{
foreach (var value in cookieValueList)
{
// 这里的 SetCookies 仅设计用来支持响应的 Cookie 解析,而不是请求的 Cookie 解析
cookieContainer.SetCookies(requestUri, value);
}
} return cookieContainer.GetCookies(requestUri);
}

为什么会是如此奇怪的设计呢?这是历史原因,我找到一篇讲的很好的答案,请看 cookie中的转义字符的方法是叫什么规范? - 知乎

参考:

关于多个 Cookie 的分隔符这件事的更多相关文章

  1. 转载:关于 Token,你应该知道的十件事

    关于 Token,你应该知道的十件事 原文地址:http://alvinzhu.me/blog/2014/08/26/10-things-you-should-know-about-tokens/ 原 ...

  2. 做一个 App 前需要考虑的几件事

    做一个 App 前需要考虑的几件事  来源:limboy的博客   随着工具链的完善,语言的升级以及各种优质教程的涌现,做一个 App 的成本也越来越低了.尽管如此,有些事情最好前期就做起来,避免当 ...

  3. 【转载】在IT界取得成功应该知道的10件事

     在IT界取得成功应该知道的10件事 2011-08-11 13:31:30 分类: 项目管理 导读:前面大多数文章都是Jack Wallen写的,这是他的新作,看来要成为NB程序员还要不停的自我总结 ...

  4. 安装完CentOS 7 后必做的七件事

    CentOS是最多人用来运行服务器的 Linux 版本,最新版本是 CentOS 7.当你兴趣勃勃地在一台主机或 VPS 上安装 CentOS 7 后,首要的工作肯定是加强它的安全性,以下列出的七件事 ...

  5. A/B 测试之前必须要了解的 10 件事

    如今,转化率优化(CRO)已是营销人员必须具备的技能,并且与 ROI 直接挂钩.但是在优化网页的转化率方面又有太多因素要考量,如果你已经不堪其忧,请专心做一件事-- A/B 测试. A/B测试,即你设 ...

  6. 关于Promise:你可能不知道的6件事

    FROM ME : 文章介绍了6个Promise的知识点: 1.then() 返回一个 forked Promise(分叉的 Promise):返回的有两种情况: 2.回调函数应该传递结果:在 pro ...

  7. Ubuntu 16.04 LTS安装好需要设置的15件事(喜欢新版本)

    看到这篇文章说明你已经从老版本升级到 Ubuntu 16.04 或进行了全新安装,在安装好 Ubuntu 16.04 LTS 之后建议大家先做如下 15 件事.无论你是刚加入 Ubuntu 行列的新用 ...

  8. 关于Web Worker你必须知道的7件事

    介绍 通过使用Web Worker, 我们可以在浏览器后台运行Javascript, 而不占用浏览器自身线程.Web Worker可以提高应用的总体性能,并且提升用户体验.如果你想在自己的Web应用中 ...

  9. 微信小程序:开发之前要知道的三件事

    前言 微信之父张小龙在年初的那次演讲中曾表示:"我自己是很多年的程序员,我觉得我们应该为开发的团队做一些事情".几个月后,微信正式推出微信应用号(即微信小程序),在互联网中掀起了又 ...

  10. <转>离婚前夜悟出的三件事

    文/铁眼(简书作者)原文链接:http://www.jianshu.com/p/832be4f659a0?utm_campaign=hugo&utm_medium=reader_share&a ...

随机推荐

  1. System design summary

    system design https://github.com/donnemartin/system-design-primer Performance vs scalability scalabi ...

  2. csproj技巧,以及使用其他类库冲突,以及引入第三方UI方式

    1.在项目中我们经常写 string? Message{get;set;} 明明是引用类型,它底下还是会出现波浪线,我们可以打开csproj 找到Nullable将它改为disable,或者删除,它默 ...

  3. WPF命令绑定

    在WPF中有时候不想将命令写在List中,但是却要在前端绑定的List中写入命令 暂时知道两种解决方法 1. Command="{Binding DataContext.NavicateCo ...

  4. Python 列表list方法clear( )和直接list [ ]的区别

    x.clear()是将内存地址清空, x=[ ]会新开辟一个内存空间.

  5. #交互,分类讨论#CF1292E Rin and The Unknown Flower

    题目传送门 分析 先尝试锁定一个字母,显然询问 \(CH,CO,CC\) 会比直接询问 \(C\) 更优,虽然牺牲了最后一个位置是否为 \(C\) 的查询. 同理,询问 \(HH,OH,CH\) 会比 ...

  6. #ST表,并查集#洛谷 3295 [SCOI2016]萌萌哒

    题目 分析 可以发现除了最高位只能填 1 到 9,其它位置还可以填 0. 直接用并查集找连通块会超时,如果将这些区间的合并可以下传到子区间的合并那样就可以了. 考虑ST表的逆操作,合并时直接合并两个极 ...

  7. #trie,动态规划#洛谷 2292 [HNOI2004]L语言

    题目 分析 建一棵trie,然后匹配最长前缀可以用\(dp\)做, 如果这个位置可以被匹配到那么可以从这个位置继续匹配 代码 #include <cstdio> #include < ...

  8. mysql系列之杂谈(一)

    从刚开始工作到现在,除了实习的时候在国企用过oracle,毕业之后陪伴我的数据库一直都是mysql,而由于mysql的开源特性,也让成为无数公司的宠儿,越走越远. 我们在刚开始使用mysql时,会发现 ...

  9. HMS Core 3D Engine助您实现逼真3D渲染效果,构筑大型3D数字世界

    HMS Core 3D Engine是一款高性能.高画质.高可靠的实时3D引擎,旨在帮助开发者制作高品质的3D应用.3D Engine将为您提供可编程渲染管线,多维粒子系统,3D角色与动画,超大地形地 ...

  10. C++获取appdata路径

    C++获取appdata路径的方式:    SHGetSpecialFolderPath wchar_t buffer[MAX_PATH]; SHGetSpecialFolderPath(0, buf ...