using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace Store.Framework.Models { /// /// Cookie集合,支持普通 Cookie 字符串和 API 返回的 Cookie JSON。 /// [JsonConverter(typeof(CookiesJsonConverter))] public class Cookies : Dictionary { private readonly string oldCookie; public Cookies(string cookie) { oldCookie = cookie; Load(cookie); } /// /// Cookie字符串 /// public string CookieString { get { return GetCookieString(); } } /// /// 获取指定值 /// /// /// 默认值 /// public string GetValue(string key, string defvalue) { if (ContainsKey(key)) { return this[key]; } return defvalue; } /// /// 添加或修改 /// /// /// public void AddOrUpdate(string key, string value) { if (!this.ContainsKey(key)) { Add(key, value); } else { this[key] = value; } } /// /// 获取Cookies字符串 /// /// public virtual string GetCookieString() { var list = this.Select(a => { return $"{a.Key}={a.Value}"; }); return string.Join(";", list); } /// /// 转为浏览器 Cookie 字符串。 /// public override string ToString() { var list = this.Select(a => { return $"{a.Key}={a.Value}"; }); return string.Join("; ", list); } /// /// 隐式转换 /// /// public static implicit operator string(Cookies cookie) { return cookie.GetCookieString(); } internal static Cookies FromToken(JToken token) { Cookies cookies = new Cookies(string.Empty); if (token == null || token.Type == JTokenType.Null) return cookies; if (token.Type == JTokenType.String) return new Cookies(token.ToString()); cookies.AddToken(token); return cookies; } private void Load(string cookie) { Clear(); if (string.IsNullOrWhiteSpace(cookie)) return; try { AddToken(JToken.Parse(cookie)); if (Count > 0) return; } catch (JsonException) { } SplitCookie(Decode(cookie)); } private void AddToken(JToken token) { if (token == null || token.Type == JTokenType.Null) return; if (token is JArray array) { foreach (JToken item in array) { AddCookie(item); } return; } AddCookie(token); } private void AddCookie(JToken token) { if (token == null || token.Type == JTokenType.Null) return; if (token.Type == JTokenType.String) { string value = token.ToString(); int index = value.IndexOf('='); if (index <= 0) return; AddOrUpdate(value.Substring(0, index).Trim(), value.Substring(index + 1).Trim()); return; } JToken name = token["Name"] ?? token["name"]; JToken valueToken = token["Value"] ?? token["value"]; if (name == null || valueToken == null) return; AddOrUpdate(name.ToString(), valueToken.ToString()); } /// /// 拆分普通 Cookie 字符串。 /// private void SplitCookie(string cookie) { Clear(); if (string.IsNullOrEmpty(cookie)) return; Regex regCookie = new Regex("(?.+?)=(?.+?)(;|$)"); if (regCookie.IsMatch(cookie)) { MatchCollection matchs = regCookie.Matches(cookie); foreach (Match item in matchs) { string key = item.Groups["key"].Value.Trim(); string value = item.Groups["value"].Value.Trim(); if (!ContainsKey(key)) { this.Add(key, value); } } } } private static string Decode(string value) { return (value ?? string.Empty) .Replace("&", "&") .Replace("%", "%") .Replace("+", "+") .Replace(""", "\""); } } /// /// Cookie JSON 转换器。 /// public class CookiesJsonConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(Cookies).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; if (reader.TokenType == JsonToken.String) return new Cookies(reader.Value?.ToString()); return Cookies.FromToken(JToken.Load(reader)); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { Cookies cookies = value as Cookies; writer.WriteValue(cookies?.GetCookieString()); } } }