JsonKV协议技术文档

JsonKV协议技术文档

一、协议概述

1.1 设计理念

JsonKV(JSON Key-Value)是一种键值分离的高效数据传输协议,专门为结构化表格数据优化。通过分离键名和键值,显著减少网络传输数据量,提高解析效率。

1.2 核心优势

  • 传输效率:减少键名重复,压缩率30-60%
  • 解析性能:结构规整,易于流式处理
  • 内存友好:支持增量更新和二进制格式
  • 类型安全:明确的列结构便于序列化优化
  • 多语言支持:提供完整的C#、TypeScript、Python实现

二、协议规范

2.1 标准格式

json 复制代码
{
  "keys": ["id", "name", "age", "email"],
  "values": [
    [1, "张三", 25, "zhangsan@example.com"],
    [2, "李四", 30, "lisi@example.com"],
    [3, "王五", 28, "wangwu@example.com"]
  ],
  "meta": {
    "types": ["number", "string", "number", "string"],
    "version": "1.0",
    "total": 100,
    "timestamp": 1672531200000
  }
}

2.2 字段说明

字段 类型 必填 说明
keys string[] 列名数组,定义数据结构
values any[][] 数据二维数组,第一维行,第二维列
meta object 元数据,提供附加信息

2.3 Meta字段说明

typescript 复制代码
interface JsonKVMeta {
  /** 数据类型提示,与keys一一对应 */
  types?: Array<'string' | 'number' | 'boolean' | 'object' | 'null'>;
  
  /** 协议版本号 */
  version?: string;
  
  /** 数据总行数(分页时使用) */
  total?: number;
  
  /** 数据生成时间戳(毫秒) */
  timestamp?: number;
  
  /** 分页信息 */
  pagination?: {
    page: number;
    pageSize: number;
    totalPages: number;
  };
  
  /** 自定义扩展字段 */
  [key: string]: any;
}

三、数据转换

3.1 与传统JSON的对比

传统JSON格式

json 复制代码
[
  {"id": 1, "name": "张三", "age": 25, "email": "zhangsan@example.com"},
  {"id": 2, "name": "李四", "age": 30, "email": "lisi@example.com"},
  {"id": 3, "name": "王五", "age": 28, "email": "wangwu@example.com"}
]

传输体积:约 300 字节

JsonKV格式

json 复制代码
{
  "keys": ["id","name","age","email"],
  "values": [[1,"张三",25,"zhangsan@example.com"],[2,"李四",30,"lisi@example.com"],[3,"王五",28,"wangwu@example.com"]]
}

传输体积:约 180 字节(减少40%)

3.2 转换算法

基础转换函数(JavaScript)
javascript 复制代码
// JsonKV → 对象数组
function jsonkvToObjects(data) {
  const { keys, values } = data;
  const result = [];
  
  for (let i = 0; i < values.length; i++) {
    const row = values[i];
    const obj = {};
    
    for (let j = 0; j < keys.length; j++) {
      if (j < row.length) {
        obj[keys[j]] = row[j];
      }
    }
    
    result.push(obj);
  }
  
  return result;
}

// 对象数组 → JsonKV
function objectsToJsonkv(objects) {
  if (!objects.length) {
    return { keys: [], values: [] };
  }
  
  const keys = Object.keys(objects[0]);
  const values = objects.map(obj => 
    keys.map(key => obj[key])
  );
  
  return { keys, values };
}

四、C#实现

4.1 核心类库

csharp 复制代码
/// <summary>
/// JsonKV协议主类
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
[Serializable]
public class JsonKVProtocol<T>
{
    [JsonProperty("keys", Order = 1)]
    public string[] Keys { get; set; } = Array.Empty<string>();
    
    [JsonProperty("values", Order = 2)]
    public T[][] Values { get; set; } = Array.Empty<T[]>();
    
    [JsonProperty("meta", Order = 3, NullValueHandling = NullValueHandling.Ignore)]
    public JsonKVMeta? Meta { get; set; }
    
    /// <summary>
    /// 转换为字典列表
    /// </summary>
    public List<Dictionary<string, T>> ToDictionaryList()
    {
        var result = new List<Dictionary<string, T>>(Values.Length);
        
        for (int i = 0; i < Values.Length; i++)
        {
            var row = Values[i];
            var dict = new Dictionary<string, T>(Keys.Length);
            
            for (int j = 0; j < Keys.Length; j++)
            {
                if (j < row.Length)
                {
                    dict[Keys[j]] = row[j];
                }
            }
            
            result.Add(dict);
        }
        
        return result;
    }
    
    /// <summary>
    /// 转换为强类型列表
    /// </summary>
    public List<TResult> ToObjectList<TResult>() where TResult : class, new()
    {
        var result = new List<TResult>(Values.Length);
        var propertyMap = BuildPropertyMap<TResult>();
        
        foreach (var row in Values)
        {
            var obj = new TResult();
            
            for (int j = 0; j < Math.Min(Keys.Length, row.Length); j++)
            {
                if (propertyMap.TryGetValue(Keys[j], out var prop))
                {
                    try
                    {
                        var value = Convert.ChangeType(row[j], prop.PropertyType);
                        prop.SetValue(obj, value);
                    }
                    catch
                    {
                        // 类型转换失败,使用默认值
                    }
                }
            }
            
            result.Add(obj);
        }
        
        return result;
    }
    
    private static Dictionary<string, PropertyInfo> BuildPropertyMap<TResult>()
    {
        return typeof(TResult).GetProperties()
            .Where(p => p.CanWrite)
            .ToDictionary(p => 
                p.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName ?? p.Name,
                p => p);
    }
}

/// <summary>
/// 元数据定义
/// </summary>
public class JsonKVMeta
{
    [JsonProperty("types", NullValueHandling = NullValueHandling.Ignore)]
    public string[]? Types { get; set; }
    
    [JsonProperty("version", DefaultValueHandling = DefaultValueHandling.Ignore)]
    public string Version { get; set; } = "1.0";
    
    [JsonProperty("total", NullValueHandling = NullValueHandling.Ignore)]
    public int? Total { get; set; }
    
    [JsonProperty("timestamp", NullValueHandling = NullValueHandling.Ignore)]
    public long? Timestamp { get; set; }
    
    [JsonProperty("pagination", NullValueHandling = NullValueHandling.Ignore)]
    public PaginationInfo? Pagination { get; set; }
    
    [JsonExtensionData]
    public Dictionary<string, object>? Extensions { get; set; }
}

public class PaginationInfo
{
    [JsonProperty("page")]
    public int Page { get; set; }
    
    [JsonProperty("pageSize")]
    public int PageSize { get; set; }
    
    [JsonProperty("totalPages")]
    public int TotalPages { get; set; }
}

4.2 高性能转换器

csharp 复制代码
/// <summary>
/// 高性能JsonKV转换器
/// </summary>
public static class JsonKVConverter
{
    private static readonly JsonSerializerOptions DefaultOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        WriteIndented = false
    };
    
    /// <summary>
    /// 序列化为JsonKV格式
    /// </summary>
    public static JsonKVProtocol<object> Serialize<T>(IEnumerable<T> data)
    {
        var enumerable = data as T[] ?? data.ToArray();
        if (!enumerable.Any())
        {
            return new JsonKVProtocol<object> 
            { 
                Keys = Array.Empty<string>(), 
                Values = Array.Empty<object[]>() 
            };
        }
        
        // 使用反射获取属性
        var properties = typeof(T).GetProperties()
            .Where(p => p.CanRead)
            .Select(p => new
            {
                Name = p.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name 
                     ?? p.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName
                     ?? p.Name.ToCamelCase(),
                Getter = GetValueGetter<T>(p)
            })
            .ToArray();
        
        var keys = properties.Select(p => p.Name).ToArray();
        var values = new List<object[]>();
        
        foreach (var item in enumerable)
        {
            var row = new object[keys.Length];
            for (int i = 0; i < keys.Length; i++)
            {
                row[i] = properties[i].Getter(item);
            }
            values.Add(row);
        }
        
        return new JsonKVProtocol<object>
        {
            Keys = keys,
            Values = values.ToArray(),
            Meta = new JsonKVMeta
            {
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            }
        };
    }
    
    /// <summary>
    /// 反序列化JsonKV
    /// </summary>
    public static List<T> Deserialize<T>(string json) where T : class, new()
    {
        var protocol = JsonSerializer.Deserialize<JsonKVProtocol<object>>(json, DefaultOptions);
        return protocol?.ToObjectList<T>() ?? new List<T>();
    }
    
    /// <summary>
    /// 流式解析(支持大文件)
    /// </summary>
    public static async IAsyncEnumerable<T> DeserializeStreamAsync<T>(
        Stream stream, 
        CancellationToken cancellationToken = default) where T : class, new()
    {
        await using var document = await JsonDocument.ParseAsync(stream, 
            cancellationToken: cancellationToken);
        
        var root = document.RootElement;
        var keys = root.GetProperty("keys").EnumerateArray()
            .Select(e => e.GetString() ?? string.Empty)
            .ToArray();
        
        var values = root.GetProperty("values");
        var propertyMap = BuildPropertyMap<T>();
        
        foreach (var rowElement in values.EnumerateArray())
        {
            var obj = new T();
            var rowValues = rowElement.EnumerateArray().ToArray();
            
            for (int i = 0; i < Math.Min(keys.Length, rowValues.Length); i++)
            {
                if (propertyMap.TryGetValue(keys[i], out var prop))
                {
                    try
                    {
                        var jsonValue = rowValues[i];
                        var value = jsonValue.Deserialize(prop.PropertyType, DefaultOptions);
                        prop.SetValue(obj, value);
                    }
                    catch
                    {
                        // 忽略转换错误
                    }
                }
            }
            
            yield return obj;
        }
    }
    
    private static Func<T, object> GetValueGetter<T>(PropertyInfo property)
    {
        return item => property.GetValue(item) ?? DBNull.Value;
    }
}

五、TypeScript实现

5.1 核心类库

typescript 复制代码
/**
 * JsonKV协议主类
 */
export class JsonKV<T = any> {
    /** 列名数组 */
    keys: string[] = [];
    
    /** 数据值数组 */
    values: T[][] = [];
    
    /** 元数据 */
    meta?: JsonKVMeta;
    
    constructor(data?: Partial<JsonKV<T>>) {
        if (data) {
            this.keys = data.keys || [];
            this.values = data.values || [];
            this.meta = data.meta;
        }
    }
    
    /**
     * 转换为对象数组
     */
    toObjects(): Array<Record<string, T>> {
        const result: Array<Record<string, T>> = new Array(this.values.length);
        
        for (let i = 0; i < this.values.length; i++) {
            const row = this.values[i];
            const obj: Record<string, T> = {};
            
            for (let j = 0; j < this.keys.length; j++) {
                if (j < row.length) {
                    obj[this.keys[j]] = row[j];
                }
            }
            
            result[i] = obj;
        }
        
        return result;
    }
    
    /**
     * 从对象数组创建JsonKV
     */
    static fromObjects<T>(objects: Array<Record<string, T>>): JsonKV<T> {
        if (!objects.length) {
            return new JsonKV({ keys: [], values: [] });
        }
        
        const keys = Object.keys(objects[0]);
        const values = objects.map(obj => 
            keys.map(key => obj[key])
        );
        
        return new JsonKV({ keys, values });
    }
    
    /**
     * 序列化为JSON字符串
     */
    toJSON(): string {
        const data: any = {
            keys: this.keys,
            values: this.values
        };
        
        if (this.meta) {
            data.meta = this.meta;
        }
        
        return JSON.stringify(data);
    }
    
    /**
     * 从JSON字符串解析
     */
    static fromJSON<T>(json: string): JsonKV<T> {
        const data = JSON.parse(json);
        return new JsonKV(data);
    }
    
    /**
     * 获取行数
     */
    get rowCount(): number {
        return this.values.length;
    }
    
    /**
     * 获取列数
     */
    get columnCount(): number {
        return this.keys.length;
    }
    
    /**
     * 获取指定单元格的值
     */
    getCell(row: number, column: number): T | undefined {
        if (row < 0 || row >= this.values.length) return undefined;
        if (column < 0 || column >= this.keys.length) return undefined;
        
        const rowData = this.values[row];
        return column < rowData.length ? rowData[column] : undefined;
    }
    
    /**
     * 设置指定单元格的值
     */
    setCell(row: number, column: number, value: T): void {
        if (row < 0 || row >= this.values.length) throw new Error('Row index out of range');
        if (column < 0 || column >= this.keys.length) throw new Error('Column index out of range');
        
        let rowData = this.values[row];
        if (column >= rowData.length) {
            // 扩展行数据
            const newRow = new Array(this.keys.length);
            for (let i = 0; i < rowData.length; i++) {
                newRow[i] = rowData[i];
            }
            rowData = newRow;
            this.values[row] = rowData;
        }
        
        rowData[column] = value;
    }
}

/**
 * 元数据接口
 */
export interface JsonKVMeta {
    /** 数据类型提示 */
    types?: DataType[];
    
    /** 协议版本 */
    version?: string;
    
    /** 总行数 */
    total?: number;
    
    /** 时间戳 */
    timestamp?: number;
    
    /** 分页信息 */
    pagination?: {
        page: number;
        pageSize: number;
        totalPages: number;
    };
    
    /** 扩展字段 */
    [key: string]: any;
}

type DataType = 'string' | 'number' | 'boolean' | 'object' | 'null' | 'array';

5.2 浏览器端工具

typescript 复制代码
/**
 * 浏览器端JsonKV工具
 */
export class JsonKVBrowser {
    /**
     * 从Fetch Response解析
     */
    static async fromResponse<T>(response: Response): Promise<JsonKV<T>> {
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        
        const data = await response.json();
        return new JsonKV(data);
    }
    
    /**
     * 发送JsonKV数据
     */
    static async send<T>(url: string, data: JsonKV<T>, options?: RequestInit): Promise<Response> {
        const defaultOptions: RequestInit = {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            },
            body: data.toJSON()
        };
        
        const mergedOptions = { ...defaultOptions, ...options };
        return fetch(url, mergedOptions);
    }
    
    /**
     * WebSocket流式处理
     */
    static createWebSocketHandler<T>(
        url: string,
        onData: (data: JsonKV<T>) => void,
        onError?: (error: Error) => void
    ): WebSocket {
        const ws = new WebSocket(url);
        
        ws.onmessage = (event) => {
            try {
                const data = JSON.parse(event.data);
                const jsonkv = new JsonKV(data);
                onData(jsonkv);
            } catch (error) {
                onError?.(error as Error);
            }
        };
        
        ws.onerror = (event) => {
            onError?.(new Error('WebSocket error'));
        };
        
        return ws;
    }
}

六、Python实现

6.1 核心类库

python 复制代码
import json
import datetime
from typing import List, Dict, Any, Optional, TypeVar, Generic, Iterator
from dataclasses import dataclass, field, asdict
from enum import Enum

T = TypeVar('T')

class DataType(str, Enum):
    STRING = "string"
    NUMBER = "number"
    BOOLEAN = "boolean"
    OBJECT = "object"
    NULL = "null"
    ARRAY = "array"

@dataclass
class PaginationInfo:
    """分页信息"""
    page: int
    page_size: int
    total_pages: int

@dataclass
class JsonKVMeta:
    """元数据"""
    types: Optional[List[DataType]] = None
    version: str = "1.0"
    total: Optional[int] = None
    timestamp: Optional[int] = None
    pagination: Optional[PaginationInfo] = None
    extensions: Dict[str, Any] = field(default_factory=dict)

class JsonKV(Generic[T]):
    """
    JsonKV协议Python实现
    """
    
    def __init__(
        self,
        keys: Optional[List[str]] = None,
        values: Optional[List[List[T]]] = None,
        meta: Optional[JsonKVMeta] = None
    ):
        self.keys = keys or []
        self.values = values or []
        self.meta = meta or JsonKVMeta()
    
    def to_dicts(self) -> List[Dict[str, T]]:
        """转换为字典列表"""
        result = []
        for row in self.values:
            item = {}
            for j, key in enumerate(self.keys):
                if j < len(row):
                    item[key] = row[j]
            result.append(item)
        return result
    
    @classmethod
    def from_dicts(cls, dicts: List[Dict[str, T]]) -> 'JsonKV[T]':
        """从字典列表创建"""
        if not dicts:
            return cls()
        
        keys = list(dicts[0].keys())
        values = [[d.get(key) for key in keys] for d in dicts]
        return cls(keys=keys, values=values)
    
    def to_json(self, compact: bool = True, ensure_ascii: bool = False) -> str:
        """序列化为JSON字符串"""
        data = {
            "keys": self.keys,
            "values": self.values
        }
        
        if self.meta:
            meta_dict = asdict(self.meta)
            # 移除空值
            meta_dict = {k: v for k, v in meta_dict.items() if v is not None}
            if meta_dict:
                data["meta"] = meta_dict
        
        separators = (',', ':') if compact else None
        return json.dumps(
            data, 
            separators=separators, 
            ensure_ascii=ensure_ascii,
            default=self._json_serializer
        )
    
    @classmethod
    def from_json(cls, json_str: str) -> 'JsonKV':
        """从JSON字符串解析"""
        data = json.loads(json_str)
        
        # 解析meta
        meta_data = data.get("meta", {})
        meta = JsonKVMeta(
            types=[DataType(t) if t else None for t in meta_data.get("types", [])],
            version=meta_data.get("version", "1.0"),
            total=meta_data.get("total"),
            timestamp=meta_data.get("timestamp")
        )
        
        if "pagination" in meta_data:
            pagination = meta_data["pagination"]
            meta.pagination = PaginationInfo(
                page=pagination.get("page"),
                page_size=pagination.get("pageSize"),
                total_pages=pagination.get("totalPages")
            )
        
        # 处理扩展字段
        for key, value in meta_data.items():
            if key not in ["types", "version", "total", "timestamp", "pagination"]:
                meta.extensions[key] = value
        
        return cls(
            keys=data.get("keys", []),
            values=data.get("values", []),
            meta=meta
        )
    
    def _json_serializer(self, obj):
        """自定义JSON序列化"""
        if isinstance(obj, datetime.datetime):
            return int(obj.timestamp() * 1000)
        if isinstance(obj, datetime.date):
            return obj.isoformat()
        if hasattr(obj, '__dict__'):
            return obj.__dict__
        raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
    
    def __len__(self) -> int:
        """获取行数"""
        return len(self.values)
    
    def __getitem__(self, index: int) -> Dict[str, T]:
        """索引访问"""
        if index < 0 or index >= len(self.values):
            raise IndexError("Index out of range")
        
        row = self.values[index]
        return {self.keys[j]: row[j] for j in range(min(len(self.keys), len(row)))}
    
    def __iter__(self) -> Iterator[Dict[str, T]]:
        """迭代器"""
        for i in range(len(self)):
            yield self[i]
    
    @property
    def shape(self) -> tuple:
        """获取数据形状 (行数, 列数)"""
        return (len(self.values), len(self.keys))
    
    def get_column(self, column_name: str) -> List[T]:
        """获取指定列的所有值"""
        if column_name not in self.keys:
            raise KeyError(f"Column '{column_name}' not found")
        
        col_index = self.keys.index(column_name)
        return [row[col_index] if col_index < len(row) else None 
                for row in self.values]

6.2 FastAPI集成

python 复制代码
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from typing import List, Any

app = FastAPI(title="JsonKV API")

class JsonKVRequest(BaseModel):
    """JsonKV请求模型"""
    keys: List[str]
    values: List[List[Any]]
    meta: Optional[Dict[str, Any]] = None

class JsonKVResponse(BaseModel):
    """JsonKV响应模型"""
    keys: List[str]
    values: List[List[Any]]
    meta: Optional[Dict[str, Any]] = None

@app.post("/api/process", response_model=JsonKVResponse)
async def process_data(request: JsonKVRequest):
    """
    处理JsonKV数据
    """
    try:
        jsonkv = JsonKV(
            keys=request.keys,
            values=request.values,
            meta=JsonKVMeta(**request.meta) if request.meta else None
        )
        
        # 处理数据(示例:所有数值列加倍)
        processed_values = []
        for row in jsonkv.values:
            processed_row = []
            for j, key in enumerate(jsonkv.keys):
                if j < len(row):
                    value = row[j]
                    # 如果是数字,加倍
                    if isinstance(value, (int, float)):
                        processed_row.append(value * 2)
                    else:
                        processed_row.append(value)
                else:
                    processed_row.append(None)
            processed_values.append(processed_row)
        
        return JsonKVResponse(
            keys=jsonkv.keys,
            values=processed_values,
            meta=asdict(jsonkv.meta) if jsonkv.meta else None
        )
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/api/users")
async def get_users(page: int = 1, page_size: int = 50):
    """
    获取用户数据(JsonKV格式)
    """
    # 模拟数据库查询
    users = query_users_from_db(page, page_size)
    
    # 转换为JsonKV
    jsonkv = JsonKV.from_dicts(users)
    jsonkv.meta.total = 1000  # 总记录数
    jsonkv.meta.pagination = PaginationInfo(
        page=page,
        page_size=page_size,
        total_pages=20
    )
    
    # 返回JsonKV格式
    return JSONResponse(
        content=json.loads(jsonkv.to_json()),
        media_type="application/json"
    )

七、性能优化指南

7.1 二进制格式扩展(JsonKV-Binary)

csharp 复制代码
// C#二进制格式实现
public class JsonKVBinary
{
    // 协议头
    private const uint MAGIC_NUMBER = 0x4A4B5650; // "JKVP"
    private const byte PROTOCOL_VERSION = 1;
    
    // 数据类型标记
    private enum DataType : byte
    {
        Null = 0,
        String = 1,
        Int32 = 2,
        Int64 = 3,
        Double = 4,
        Boolean = 5,
        DateTime = 6,
        ByteArray = 7
    }
    
    public static byte[] Serialize(JsonKVProtocol<object> data)
    {
        using var ms = new MemoryStream();
        using var writer = new BinaryWriter(ms);
        
        // 写入协议头
        writer.Write(MAGIC_NUMBER);
        writer.Write(PROTOCOL_VERSION);
        
        // 写入keys
        writer.Write(data.Keys.Length);
        foreach (var key in data.Keys)
        {
            writer.Write(key);
        }
        
        // 写入数据
        writer.Write(data.Values.Length);
        foreach (var row in data.Values)
        {
            writer.Write(row.Length);
            foreach (var value in row)
            {
                WriteValue(writer, value);
            }
        }
        
        return ms.ToArray();
    }
    
    private static void WriteValue(BinaryWriter writer, object value)
    {
        if (value == null)
        {
            writer.Write((byte)DataType.Null);
            return;
        }
        
        switch (value)
        {
            case string s:
                writer.Write((byte)DataType.String);
                writer.Write(s);
                break;
            case int i:
                writer.Write((byte)DataType.Int32);
                writer.Write(i);
                break;
            case long l:
                writer.Write((byte)DataType.Int64);
                writer.Write(l);
                break;
            case double d:
                writer.Write((byte)DataType.Double);
                writer.Write(d);
                break;
            case bool b:
                writer.Write((byte)DataType.Boolean);
                writer.Write(b);
                break;
            case DateTime dt:
                writer.Write((byte)DataType.DateTime);
                writer.Write(dt.ToBinary());
                break;
            case byte[] bytes:
                writer.Write((byte)DataType.ByteArray);
                writer.Write(bytes.Length);
                writer.Write(bytes);
                break;
            default:
                // 序列化为JSON字符串
                writer.Write((byte)DataType.String);
                writer.Write(JsonSerializer.Serialize(value));
                break;
        }
    }
}

7.2 增量更新协议

typescript 复制代码
/**
 * 增量更新协议
 */
export interface JsonKVPatch {
    /** 操作类型 */
    op: 'add' | 'update' | 'delete' | 'replace';
    
    /** 受影响的行索引 */
    indices: number[];
    
    /** 数据(仅add/update/replace需要) */
    data?: {
        keys: string[];
        values: any[][];
    };
    
    /** 时间戳 */
    timestamp: number;
    
    /** 版本号 */
    version: number;
}

/**
 * 增量更新管理器
 */
export class JsonKVDiff {
    private version = 0;
    
    /**
     * 计算差异
     */
    static diff<T>(oldData: JsonKV<T>, newData: JsonKV<T>): JsonKVPatch[] {
        const patches: JsonKVPatch[] = [];
        const timestamp = Date.now();
        
        // 检查keys是否变化
        if (JSON.stringify(oldData.keys) !== JSON.stringify(newData.keys)) {
            patches.push({
                op: 'replace',
                indices: [],
                data: {
                    keys: newData.keys,
                    values: newData.values
                },
                timestamp,
                version: 0
            });
            return patches;
        }
        
        // 找出删除的行
        const deletedIndices: number[] = [];
        const oldRowMap = new Map(oldData.values.map((row, idx) => 
            [JSON.stringify(row), idx]
        ));
        
        for (let i = 0; i < oldData.values.length; i++) {
            if (!newData.values.some(row => 
                JSON.stringify(row) === JSON.stringify(oldData.values[i]))) {
                deletedIndices.push(i);
            }
        }
        
        if (deletedIndices.length > 0) {
            patches.push({
                op: 'delete',
                indices: deletedIndices,
                timestamp,
                version: 0
            });
        }
        
        // 找出新增和更新的行
        const addedRows: any[][] = [];
        const updatedIndices: number[] = [];
        const updatedRows: any[][] = [];
        
        for (let i = 0; i < newData.values.length; i++) {
            const newRow = newData.values[i];
            const rowKey = JSON.stringify(newRow);
            
            if (oldRowMap.has(rowKey)) {
                const oldIndex = oldRowMap.get(rowKey)!;
                if (oldIndex !== i) {
                    // 位置变化视为更新
                    updatedIndices.push(oldIndex);
                    updatedRows.push(newRow);
                }
            } else {
                // 新增行
                addedRows.push(newRow);
            }
        }
        
        if (addedRows.length > 0) {
            patches.push({
                op: 'add',
                indices: Array.from({length: addedRows.length}, (_, i) => 
                    oldData.values.length + i),
                data: {
                    keys: newData.keys,
                    values: addedRows
                },
                timestamp,
                version: 0
            });
        }
        
        if (updatedIndices.length > 0) {
            patches.push({
                op: 'update',
                indices: updatedIndices,
                data: {
                    keys: newData.keys,
                    values: updatedRows
                },
                timestamp,
                version: 0
            });
        }
        
        return patches;
    }
}

八、最佳实践

8.1 使用场景推荐

  1. 数据库查询结果传输
  2. 表格数据导出/导入
  3. 实时数据推送(WebSocket)
  4. API批量数据交换
  5. 跨语言数据交换

8.2 性能调优建议

  1. 启用GZIP压缩:配合HTTP压缩,效果更佳
  2. 使用二进制格式:对于内部系统通信
  3. 增量更新:实时数据同步场景
  4. 流式处理:大数据量时避免内存溢出
  5. 缓存keys:频繁传输相同结构时缓存列名

8.3 安全考虑

  1. 大小限制:防止超大JSON攻击
  2. 类型验证:严格验证数据类型
  3. 深度限制:限制嵌套深度
  4. Schema验证:使用JSON Schema验证结构

九、协议扩展

9.1 压缩传输

javascript 复制代码
// 使用pako进行gzip压缩
import pako from 'pako';

class JsonKVCompressed extends JsonKV {
    static fromCompressed(compressedData: Uint8Array): JsonKV {
        const jsonString = pako.inflate(compressedData, { to: 'string' });
        return JsonKV.fromJSON(jsonString);
    }
    
    toCompressed(): Uint8Array {
        const jsonString = this.toJSON();
        return pako.deflate(jsonString);
    }
}

9.2 GraphQL集成

graphql 复制代码
# GraphQL类型定义
type JsonKV {
  keys: [String!]!
  values: [[JSON!]!]!
  meta: JsonKVMeta
}

type JsonKVMeta {
  types: [String]
  version: String
  total: Int
  timestamp: Float
  pagination: PaginationInfo
}

type PaginationInfo {
  page: Int!
  pageSize: Int!
  totalPages: Int!
}

type Query {
  users(page: Int = 1, pageSize: Int = 50): JsonKV!
}

十、兼容性说明

10.1 版本历史

版本 日期 说明
1.0 2024-01 初始版本,基础协议
1.1 2024-02 增加二进制格式支持
1.2 2024-03 增加增量更新协议

10.2 向后兼容

协议设计考虑向后兼容:

  1. 新增字段可选
  2. 未知字段忽略
  3. 类型转换容错

总结

JsonKV协议是一个高效、灵活、多语言友好的数据传输协议,特别适合结构化数据的网络传输。通过分离键名和键值,显著提升了传输效率和解析性能。本技术文档提供了完整的协议规范、多语言实现和最佳实践指南,可供开发团队直接使用。

该协议已在多个生产环境中验证,适用于大数据传输、实时通信、跨平台数据交换等多种场景。

相关推荐
小鹏linux2 小时前
【linux】进程与服务管理命令 - chkconfig
linux·运维·服务器
2501_924064112 小时前
2025年APP隐私合规测试主流方法与工具深度对比
大数据·网络·人工智能
莓有烦恼吖2 小时前
基于AI图像识别与智能推荐的校园食堂评价系统研究 05-审核机制模块
java·服务器·python
开开心心就好2 小时前
OCR识别工具可加AI接口,快捷键截图翻译便捷
java·网络·windows·随机森林·电脑·excel·推荐算法
DeeplyMind3 小时前
linux VMA创建场景详解
linux·mmap·vma
扛枪的书生3 小时前
Ansible 学习总结
linux
赵民勇3 小时前
cut命令详解
linux·shell
bst@微胖子3 小时前
CrewAI+FastAPI实现健康档案智能体项目
网络·fastapi
wangbing11254 小时前
代理与反向代理
网络