Base64格式异常致部分GZip解压失败的技术求助
问题:部分Base64编码的GZIP压缩字符串解压失败
我尝试解压存储在List<string>中的压缩数据,Decompress方法如下:
static string Decompress(string inputStr) { StringBuilder result = new StringBuilder(); string decompressedString = string.Empty; byte[] compressedBytes = new byte[0]; try { compressedBytes = Convert.FromBase64String(inputStr); } catch { failedDecompressionCnt++; } using (var compressedStream = new MemoryStream(compressedBytes)) using (var decompressedStream = new MemoryStream()) using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress)) { byte[] buffer = new byte[4096]; int read; while ((read = gzip.Read(buffer, 0, buffer.Length)) > 0) { decompressedStream.Write(buffer, 0, read); } byte[] decompressedBytes = decompressedStream.ToArray(); decompressedString = Encoding.UTF8.GetString(decompressedBytes); } result.Append(decompressedString); return result.ToString(); }
在Convert.FromBase64String(inputStr)行设置断点时,发现以下inputStr触发了catch块:
H4sIAAAAAAAACr1TXU/CMBR9xsT/0Oyd9Y5lhJEyQoaJJIKLEkx8q6xIwz5I2xn993YtmRuKDz74eE/PvTn33FMyfc8z9MaE5GUxcTwXHMSKbZny4nXiVGrX94bONLq+ImsmVcyE4ju+pYppqGewByarTMm6tsD9kQmq9DgD9ciK5iy65SgpFcGmsHhChS4UE7Y+EReFHmfakZ7MpaLFliGv3dkjseC6j9PIA1giqhC4AcBhQ3DzcmJuaFaxaBhCsETlPifYAlYBPpNwQdIsRk9c7WspKao3vCAGfBcgn9V6tI+/6QHPHY2Qpv5Jz88WDf7HInvuKKFSspTgU2mOj79d30KthJiALIpdKfKviBDbUwqjvziUkhdU7TnBnQdDXSiWx2XKomc/gD54gU5GgxnGY71btqryF625xergTVjXH0cW3d3MkVSCH5Ey120eGtq8TvwABj4GD0OIIBz74RgAJUtLNwS7jP5MNMvOfOqijTVdKyzW/mSfVCx3kZ8DAAA=1
抛出的异常为:
System.FormatException: 'The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.'
遍历约52000条压缩数据逐个解压,其中约1500条出现该异常,其余均可正常解压。所有数据均通过同一Compress方法生成,Compress方法如下:
static string Compress(string inputStr, long cnt) { StringBuilder result = new StringBuilder(); byte[] inputStrBytes = Encoding.UTF8.GetBytes(inputStr); using (var stream = new MemoryStream()) using (var gzip = new GZipStream(stream, CompressionMode.Compress)) { gzip.Write(inputStrBytes, 0, inputStrBytes.Length); gzip.Close(); byte[] compressed = stream.ToArray(); result.Append(Convert.ToBase64String(compressed)); Console.WriteLine(cnt); } return result.ToString(); }
恳请协助排查原因。
排查与解决方案
1. 直接问题:无效的Base64字符串
观察出错的inputStr末尾多了一个1字符,这是非法的Base64字符(Base64仅允许A-Z、a-z、0-9、+、/,以及作为填充的=),这直接导致Convert.FromBase64String抛出异常。
2. 为何会出现额外字符?
可能的原因:
- 数据存储/传输过程中的污染:比如写入数据库时被截断或追加了额外字符,或者网络传输中出现了数据拼接错误。
- 数据读取错误:读取存储的压缩字符串时,可能读取到了相邻数据的内容,比如批量读取时边界处理不当,把下一条数据的开头字符追加到了当前字符串末尾。
- Compress方法的潜在隐患:当前Compress代码逻辑上不会生成额外字符,但需确认是否在存储返回结果时,不小心追加了其他内容(比如日志编号、计数器值)。
3. 临时修复与长期解决方案
临时修复(针对已污染的数据):
在Decompress方法中先清理非法字符,保留有效的Base64部分:
try { // 仅保留Base64允许的字符 var cleanInput = new string(inputStr.Where(c => char.IsLetterOrDigit(c) || c == '+' || c == '/' || c == '=').ToArray()); // 确保Base64长度为4的倍数,不足补填充符 while (cleanInput.Length % 4 != 0) { cleanInput += '='; } compressedBytes = Convert.FromBase64String(cleanInput); } catch { failedDecompressionCnt++; }
长期解决方案:
- 校验压缩后的数据:在Compress方法返回前,对生成的Base64字符串进行格式校验;存储前可添加校验和(如MD5),读取时验证数据完整性。
- 排查存储/读取全链路:检查数据写入、存储、读取的所有环节,确认是否存在数据追加、截断、拼接错误的情况。
- 优化Compress方法:移除不必要的
StringBuilder,直接返回Base64结果,减少潜在错误点:
static string Compress(string inputStr, long cnt) { byte[] inputStrBytes = Encoding.UTF8.GetBytes(inputStr); using (var stream = new MemoryStream()) { using (var gzip = new GZipStream(stream, CompressionMode.Compress)) { gzip.Write(inputStrBytes, 0, inputStrBytes.Length); } // using块会自动关闭gzip,无需手动调用Close byte[] compressed = stream.ToArray(); Console.WriteLine(cnt); return Convert.ToBase64String(compressed); } }
内容的提问来源于stack exchange,提问作者Nikola Matic
相关产品推荐
相关产品推荐

