天天看點

詳解Asp.Net Core中的Cookies詳解Asp.Net Core中的cookies

目錄

我之前寫過一篇文章來介紹cookies,如果你對cookies不是很了解請移步

了解cookies

這篇文章,這對于我們研究asp.net core中的cookies可以起到很大的幫助。

cookies是http協定中header頭的一部分,伺服器與用戶端的cookies傳遞都是通過header頭完成的,那麼asp.net core隻不過是對http協定的一種實作而已。

要從http中擷取cookies,首先我們要擷取header頭資訊,而這部分資訊asp.net core已經為我們準備好了,并且也幫我們解析了header頭中cookies,我們隻需要通過

HttpContext.Request.Cookies

就可以擷取所有的cookies資訊。

接下來我們主要研究一下asp.net core是如何做的,在這裡語言是否顯得蒼白許多,我們盡量以貼代碼為主:

public abstract class HttpRequest
{
    ...
    public abstract IRequestCookieCollection Cookies { get; set; }
    ...
}           

從代碼可以可看出Cookies是一個

IRequestCookieCollection

接口類型,它的實作類型為

RequestCookieCollection

,接口代碼如下:

//從接口代碼看該類是一個隻讀類,為什麼會是隻讀類,這也不難了解,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對象的 DefaultHttpRequest 是如何實作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 才是真正觸發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)
    {
      ...
    }
 }           

  • 我們先來看看Response.Cookies.Append是如何實作的

    Response.Cookies是一個HttpRespnse對象,而

    ResponseCookies 則是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的實作 HttpResponseHeaders 負責将header資訊寫入響應流
    public partial class HttpResponseHeaders : HttpHeaders
    { 
       internal void CopyTo(ref BufferWriter<PipeWriter> buffer)
            {
              //這個方将負責将headers通過流的形式寫入響應結果        
                CopyToFast(ref buffer);
                ...
            }
    }           

​ 本文介紹了,我對cookies的了解,以及asp.net core中cookies是怎麼實作的,對于所有web架構的實作都是大同小異的,如果還有什麼不明的地方最好自己能多讀幾遍代碼,多看多思考,最總一切問題都會迎刃而解。

繼續閱讀