目录
详解 Asp.Net Core 中的 cookies
搞懂 cookies
Asp.Net 中 cookies 的实现
从 http 中获取 cookies
将 cookies 写入 http 中
总结及感想
详解 Asp.Net Core 中的 cookies
搞懂 cookies
我之前写过一篇文章来介绍 cookies, 如果你对 cookies 不是很了解请移步理解 cookies https://www.cnblogs.com/guodf/p/9609404.html 这篇文章, 这对于我们研究 asp.net core 中的 cookies 可以起到很大的帮助.
Asp.Net 中 cookies 的实现
cookies 是 http 协议中 header 头的一部分, 服务器与客户端的 cookies 传递都是通过 header 头完成的, 那么 asp.net core 只不过是对 http 协议的一种实现而已.
从 http 中获取 cookies
要从 http 中获取 cookies, 首先我们要获取 header 头信息, 而这部分信息 asp.net core 已经为我们准备好了, 并且也帮我们解析了 header 头中 cookies, 我们只需要通过 HttpContext.Request.Cookies 就可以获取所有的 cookies 信息.
接下来我们主要研究一下 asp.net core 是如何做的, 在这里语言是否显得苍白许多, 我们尽量以贴代码为主:
首先, 我们从
HttpContext.Request.Cookies
https://github.com/aspnet/HttpAbstractions/blob/master/src/Microsoft.AspNetCore.Http.Abstractions/HttpRequest.cs 对象下手
- public abstract class HttpRequest
- {
- ...
- public abstract IRequestCookieCollection Cookies {get; set;}
- ...
- }
从代码可以可看出 Cookies 是一个 https://github.com/aspnet/HttpAbstractions/blob/master/src/Microsoft.AspNetCore.Http.Features/IRequestCookieCollection.cs 接口类型, 它的实现类型为 https://github.com/aspnet/HttpAbstractions/blob/master/src/Microsoft.AspNetCore.Http/Internal/RequestCookieCollection.cs , 接口代码如下:
- // 从接口代码看该类是一个只读类, 为什么会是只读类, 这也不难理解, Request 是一个请求对象, 也就是客户端发往服务器的数据, 因为这些数据是供我们来读取验证用的, 所以修改并没有什么意义
- public interface IRequestCookieCollection : IEnumerable<KeyValuePair<string, string>>, IEnumerable
- {
- string this[string key] { get; }
- int Count { get; }
- ICollection<string> Keys { get; }
- bool ContainsKey(string key);
- bool TryGetValue(string key, out string value);
- }
然后, 我们再来分析 header 中的 cookies 是如何被解析到 Request 中的 Cookies 对象的
https://github.com/aspnet/HttpAbstractions/blob/master/src/Microsoft.AspNetCore.Http/Internal/DefaultHttpRequest.cs 是如何实现 HttpRequest 的:
- public class DefaultHttpRequest : HttpRequest
- {
- ...
- // 这是一个委托对象, 用于生成 RequestCookiesFeature 实例
- private readonly static Func<IFeatureCollection, IRequestCookiesFeature> _newRequestCookiesFeature = f => new RequestCookiesFeature(f);
- ...
- // 这个方法属性展示了如何去实例化 RequestCookiesFeature 对象
- private IRequestCookiesFeature RequestCookiesFeature =>_features.Fetch(ref _features.Cache.Cookies, _newRequestCookiesFeature);
- // 这里直接调用 RequestCookiesFeature
- public override IRequestCookieCollection Cookies
- {
- get { return RequestCookiesFeature.Cookies; }
- set { RequestCookiesFeature.Cookies = value; }
- }
- }
RequestCookiesFeature.Cookies https://github.com/aspnet/HttpAbstractions/blob/master/src/Microsoft.AspNetCore.Http/Features/RequestCookiesFeature.cs 才是真正触发 cookies 解析的地方:
- public class RequestCookiesFeature : IRequestCookiesFeature
- {
- public IRequestCookieCollection Cookies
- {
- get
- {
- ...
- // 从请求中获取 header 信息, headers 是一个 IDictionary<string,StringValues > 类型
- var headers = HttpRequestFeature.Headers;
- StringValues current;
- // 从 headers 字典类型中获取 cookies 的信息, 这里获取的 current 结果是个字符串类型
- if (!headers.TryGetValue(HeaderNames.Cookie, out current))
- {
- current = string.Empty;
- }
- if (_parsedValues == null || _original != current)
- {
- _original = current;
- // 这里开始将 cookies 字符串解析为 cookies 集合类型
- _parsedValues = RequestCookieCollection.Parse(current.ToArray());
- }
- }
- }
- //RequestCookieCollection.Parse 代码如下:
- public class RequestCookieCollection : IRequestCookieCollection
- {
- public static RequestCookieCollection Parse(IList<string> values)
- {
- ...
- IList<CookieHeaderValue> cookies;
- // 最有用的一句代码在这里, 将字符串集合解析为 IList<CookieHeaderValue>
- if (CookieHeaderValue.TryParseList(values, out cookies))
- {
- ...
- }
- ...
- }
- }
最终, CookieHeaderParser 才是真正干活的地方:
- internal class CookieHeaderParser : HttpHeaderParser<CookieHeaderValue>
- {
- public sealed override bool TryParseValue(StringSegment value, ref int index, out CookieHeaderValue parsedValue)
- {
- ...
- }
- }
将 cookies 写入 http 中
我们先来看看 Response.Cookies.Append 是如何实现的
Response.Cookies 是一个 HttpRespnse 对象, 而 https://github.com/aspnet/HttpAbstractions/blob/master/src/Microsoft.AspNetCore.Http/Internal/ResponseCookies.cs 则是 IResponseCookies 的默认实现
- public class ResponseCookies : IResponseCookies
- {
- // 通过 Append 方法来添加 cookie
- public void Append(string key, string value)
- {
- // 这里构造一个 cookie 对象
- var setCookieHeaderValue = new SetCookieHeaderValue(
- Uri.EscapeDataString(key),
- Uri.EscapeDataString(value))
- {
- Path = "/"
- };
- // 然后 cookie 对象序列化字符串, 因为在 http 协议中 cookie 的值就是字符串
- var cookieValue = setCookieHeaderValue.ToString();
- // 最后将 cookie 字符串添加到 Headers 中, StringValues.Concat 将两个字符串转换成 string[]
- //Headers 是个字典类型, 所有 header 中数据都是以 k-v 的形式保存在这个字典中
- Headers[HeaderNames.SetCookie] = StringValues.Concat(Headers[HeaderNames.SetCookie], cookieValue);
- }
看一下 Headers 的实现
https://github.com/aspnet/KestrelHttpServer/blob/release/2.2/src/Kestrel.Core/Internal/Http/HttpResponseHeaders.cs 负责将 header 信息写入响应流
- public partial class HttpResponseHeaders : HttpHeaders
- {
- internal void CopyTo(ref BufferWriter<PipeWriter> buffer)
- {
- // 这个方将负责将 headers 通过流的形式写入响应结果
- CopyToFast(ref buffer);
- ...
- }
- }
总结及感想
? 本文介绍了, 我对 cookies 的理解, 以及 asp.net core 中 cookies 是怎么实现的, 对于所有 web 框架的实现都是大同小异的, 如果还有什么不明的地方最好自己能多读几遍代码, 多看多思考, 最总一切问题都会迎刃而解.
来源: http://www.bubuko.com/infodetail-2760055.html