You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何加密含多DeepLinkDataDto的深度链接且不超URL字符限制?

问题描述

当尝试对包含20个以上DeepLinkDataDto的DeepLinkModel进行加密时,生成的加密字符串过长,超出URL字符上限,导致浏览器打开深度链接时报错:

"The resource you are looking for has been removed, had its name changed, or is temporarily unavailable."

当前加密逻辑代码:

var deepLinkQueryString 
    = DeepLinkDataProtectionProvider
    .EncryptString(deepLinkModel.AsJson(), deepLinkModelEncryptionKey)

现有加密解密类:

public static class DeepLinkDataProtectionProvider
{
    private static readonly byte[] InitializationVector 
        = new byte[] 
        { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

    /// <summary>
    /// Encrypt invoice deep link query string
    /// </summary>
    /// <param name="text">string text</param>
    /// <param name="key">string key</param>
    /// <returns>Encrypted string</returns>
    public static string EncryptString(string text, string key)
    {
        byte[] array;

        // Create a new instance of the Aes
        // class.  This generates a new key and initialization
        using (Aes aes = Aes.Create())
        {
            aes.Key = Encoding.UTF8.GetBytes(key);

            // Create an encryptor to perform the stream transform.
            ICryptoTransform encryptor 
                = aes.CreateEncryptor(aes.Key, InitializationVector);

            // Create the streams used for encryption.
            using (MemoryStream memoryStream = new())
            {
                using (CryptoStream cryptoStream 
                    = new(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter streamWriter = new(cryptoStream))
                    {
                        //Write all data to the stream.
                        streamWriter.Write(text);
                    }

                    array = memoryStream.ToArray();
                }
            }
        }
        // Return the encrypted bytes from the memory stream.
        return Convert.ToBase64String(array);

    }

    /// <summary>
    /// Decrypt invoice deep link query string
    /// </summary>
    /// <param name="cipherText">string cipherText</param>
    /// <param name="key">string key</param>
    /// <returns>Decrypted string</returns>
    public static string DecryptString(string cipherText, string key)
    {
        byte[] buffer = Convert.FromBase64String(cipherText.Replace(" ", "+"));

        // Create an Aes object
        // with the specified key and IV.
        using (Aes aes = Aes.Create())
        {
            aes.Key = Encoding.UTF8.GetBytes(key);

            // Create a decryptor to perform the stream transform.
            ICryptoTransform decryptor 
                = aes.CreateDecryptor(aes.Key, InitializationVector);

            // Create the streams used for decryption.
            using (MemoryStream memoryStream = new(buffer))
            {
                using (CryptoStream cryptoStream 
                    = new(memoryStream, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader streamReader = new(cryptoStream))
                    {
                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        return streamReader.ReadToEnd();
                    }
                }
            }
        }
    }
}     

待加密模型类:

public class DeepLinkModel
{
   
    [JsonProperty("RequestId")]
    public string RequestId { get; set; }

    
    [JsonProperty("UserId")]
    public string UserId { get; set; }

    
    [JsonProperty("Code")]
    public int Code { get; set; }

    
    [JsonProperty("Data")]
    public IEnumerable<DeepLinkDataDto> Data { get; set; }
}

   
public class DeepLinkDataDto
{
   
    [JsonProperty("BillNumber")]
    public string BillNumber { get; set; }

   
    [JsonProperty("InvoiceNumber")]
    public string InvoiceNumber { get; set; }

  
    [JsonProperty("BillId")]
    public int BillId { get; set; }
}

解决方案

1. 压缩后再加密

在加密前对JSON字符串进行GZIP压缩,大幅减少原始数据体积,再对压缩后的字节流加密,而非直接加密JSON字符串。

修改EncryptString方法:

public static string EncryptString(string text, string key)
{
    byte[] array;

    using (Aes aes = Aes.Create())
    {
        aes.Key = Encoding.UTF8.GetBytes(key);
        ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, InitializationVector);

        using (MemoryStream memoryStream = new())
        {
            // 先压缩JSON文本
            using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, leaveOpen: true))
            using (StreamWriter streamWriter = new(gzipStream))
            {
                streamWriter.Write(text);
            }

            // 对压缩后的字节执行加密
            memoryStream.Position = 0;
            using (CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Read))
            using (MemoryStream encryptedStream = new())
            {
                cryptoStream.CopyTo(encryptedStream);
                array = encryptedStream.ToArray();
            }
        }
    }
    // 改用URL安全的Base64Url编码,避免转义增加长度
    return Convert.ToBase64String(array).Replace('+', '-').Replace('/', '_').Replace("=", "");
}

对应修改DecryptString方法,先解密再解压:

public static string DecryptString(string cipherText, string key)
{
    // 还原Base64Url为标准Base64格式
    cipherText = cipherText.Replace('-', '+').Replace('_', '/');
    switch (cipherText.Length % 4)
    {
        case 2: cipherText += "=="; break;
        case 3: cipherText += "="; break;
    }

    byte[] buffer = Convert.FromBase64String(cipherText);
    string result;

    using (Aes aes = Aes.Create())
    {
        aes.Key = Encoding.UTF8.GetBytes(key);
        ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, InitializationVector);

        using (MemoryStream memoryStream = new(buffer))
        using (CryptoStream cryptoStream = new(memoryStream, decryptor, CryptoStreamMode.Read))
        // 解密后解压还原原始JSON
        using (GZipStream gzipStream = new(cryptoStream, CompressionMode.Decompress))
        using (StreamReader streamReader = new(gzipStream))
        {
            result = streamReader.ReadToEnd();
        }
    }
    return result;
}

2. 使用Base64Url编码替代标准Base64

标准Base64的+、/、=字符在URL中需要URL转义,会额外增加字符串长度。改用Base64Url编码(替换+为-,/为_,去掉=填充),既符合URL安全要求,又减少最终字符数。

3. 优化JSON序列化体积

序列化DeepLinkModel时,使用紧凑配置减少JSON体积:

// 配置序列化选项,生成无空格的紧凑JSON
var jsonSettings = new JsonSerializerSettings
{
    Formatting = Formatting.None,
    // 可选:使用短属性名进一步压缩,比如将"RequestId"改为"rid",需同步修改模型JsonProperty特性
    // ContractResolver = new CustomShortNameContractResolver()
};
var compactJson = JsonConvert.SerializeObject(deepLinkModel, jsonSettings);
var deepLinkQueryString = DeepLinkDataProtectionProvider.EncryptString(compactJson, deepLinkModelEncryptionKey);

4. 备选方案:后端存储+短标识

如果数据量极大,压缩加密后仍超出URL限制,可将完整数据存储到后端缓存/数据库,用短ID作为链接参数:

// 生成唯一标识并存储数据
var dataId = Guid.NewGuid().ToString();
// 设置合理过期时间,避免缓存堆积
Cache.Set(dataId, deepLinkModel, TimeSpan.FromHours(24));

// 生成深度链接时使用短ID
var deepLinkQueryString = $"dataId={dataId}";

// 后端处理链接时还原数据
var deepLinkModel = Cache.Get<DeepLinkModel>(dataId);
if (deepLinkModel == null)
{
    // 处理数据过期或不存在的情况
}

内容的提问来源于stack exchange,提问作者Rakesh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 07:53:09