229 lines
6.3 KiB
C#
229 lines
6.3 KiB
C#
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text.RegularExpressions;
|
||
|
||
namespace Store.Framework.Models
|
||
{
|
||
/// <summary>
|
||
/// Cookie集合,支持普通 Cookie 字符串和 API 返回的 Cookie JSON。
|
||
/// </summary>
|
||
[JsonConverter(typeof(CookiesJsonConverter))]
|
||
public class Cookies : Dictionary<string, string>
|
||
{
|
||
private readonly string oldCookie;
|
||
|
||
public Cookies(string cookie)
|
||
{
|
||
oldCookie = cookie;
|
||
Load(cookie);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Cookie字符串
|
||
/// </summary>
|
||
public string CookieString
|
||
{
|
||
get
|
||
{
|
||
return GetCookieString();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定值
|
||
/// </summary>
|
||
/// <param name="key"></param>
|
||
/// <param name="defvalue">默认值</param>
|
||
/// <returns></returns>
|
||
public string GetValue(string key, string defvalue)
|
||
{
|
||
if (ContainsKey(key))
|
||
{
|
||
return this[key];
|
||
}
|
||
return defvalue;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加或修改
|
||
/// </summary>
|
||
/// <param name="key"></param>
|
||
/// <param name="value"></param>
|
||
public void AddOrUpdate(string key, string value)
|
||
{
|
||
if (!this.ContainsKey(key))
|
||
{
|
||
Add(key, value);
|
||
}
|
||
else
|
||
{
|
||
this[key] = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取Cookies字符串
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public virtual string GetCookieString()
|
||
{
|
||
var list = this.Select(a => { return $"{a.Key}={a.Value}"; });
|
||
return string.Join(";", list);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转为浏览器 Cookie 字符串。
|
||
/// </summary>
|
||
public override string ToString()
|
||
{
|
||
var list = this.Select(a => { return $"{a.Key}={a.Value}"; });
|
||
return string.Join("; ", list);
|
||
}
|
||
/// <summary>
|
||
/// 隐式转换
|
||
/// </summary>
|
||
/// <param name="cookie"></param>
|
||
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());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 拆分普通 Cookie 字符串。
|
||
/// </summary>
|
||
private void SplitCookie(string cookie)
|
||
{
|
||
Clear();
|
||
if (string.IsNullOrEmpty(cookie))
|
||
return;
|
||
|
||
Regex regCookie = new Regex("(?<key>.+?)=(?<value>.+?)(;|$)");
|
||
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(""", "\"");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Cookie JSON 转换器。
|
||
/// </summary>
|
||
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());
|
||
}
|
||
}
|
||
} |