【问题标题】:What can cause Base64 decoding throw FormatException什么会导致 Base64 解码抛出 FormatException
【发布时间】:2019-04-03 23:58:48
【问题描述】:

我正在使用 C# 和 .NET 对 base64 字符串进行编码和解码。以下是我的代码的sn-ps:

Base64 编码:

using (var stream = new MemoryStream())
        …...
    return Convert.ToBase64String(stream.ToArray());
}

Base64 解码

byte[] bytes = Convert.FromBase64String(messageBody);

我的代码在 99% 的情况下都失败了,但只有 1% 的机会成功。堆栈跟踪如下:

返回 5xx 错误:System.FormatException:输入不是有效的 Base-64 字符串,因为它包含非 base 64 字符、两个以上的填充字符或填充字符中的非法字符。在 System.Convert.FromBase64_ComputeResultLength(Char inputPtr, Int32 inputLength) 在 System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) 在 System.Convert.FromBase64String(String s)*

有谁知道什么会导致base64解码失败?我的编码和解码方法是对称的,我真的很困惑这个问题的根本原因是什么?

【问题讨论】:

  • 您是如何收到messageBody 变量的?它是否包含文字换行符或其他非 base64 字符?您需要传递 base64 字符串,并且只传递 base64 字符串。
  • 它是通过一些排队实现的;我们将编码后的 base64 字符串发送到队列并接收它并通过 base64 解码来使用它。
  • 让我重新表述一下,请包括加载 messageBody 变量的代码和失败的 messageBody 文本示例。显然它包含无效字符并导致错误。所以问题在于您传输数据或读取数据。
  • 如果您能提供minimal reproducible example,那就太好了。向我们展示messageBody 的准确 值至关重要。当它失败时。如果您不知道,我建议您在失败时将其记录下来。此外,请务必记录 messageBody 的 Length,以防有隐藏的空白字符。
  • What can cause Base64 decoding throw FormatException 如果您要求它解码一个不是有效的base64编码字符串的字符串,就会发生这种情况。

标签: c# .net base64


【解决方案1】:

为了调试这样的问题,我通常会编写一些测试或创建控制台应用程序来观察变量在函数之间的变化。

base64 解码失败的一种可能情况是解码器输入是 HTMLEncoded。例如,当您将加密字符串传递到 URL 时,这很常见。它将自动进行 HTML 编码,然后根据编码输出的字符,有时可以解码,有时不能解码。

这是一个简单的控制台应用程序来演示这一点。

class Program
{
    static void Main(string[] args)
    {
        string input = "testaa";

        TestEncodeDecode("test");
        TestEncodeDecode("testa");
        TestEncodeDecode("testaa");

        Console.ReadLine();
    }

    private static void TestEncodeDecode(string input)
    {
        string encoded = Encode(input);

        Console.WriteLine($"Encoded: {encoded}");

        string htmlEncoded = WebUtility.UrlEncode(encoded);

        Console.WriteLine($"htmlEncoded: {htmlEncoded}");

        string decodedString = Decode(htmlEncoded);

        Console.WriteLine($"Decoded: {decodedString}");

        Console.WriteLine();
    }

    private static string Decode(string htmlEncoded)
    {
        try
        {
            byte[] decoded = Convert.FromBase64String(htmlEncoded);

            return Encoding.ASCII.GetString(decoded);
        }
        catch(Exception)
        {
            return "Decoding failed";
        }
    }

    private static string Encode(string input)
    {
        byte[] bytes = Encoding.ASCII.GetBytes(input);
        using (var stream = new MemoryStream())
        {
            stream.Write(bytes);
            return Convert.ToBase64String(stream.ToArray());
        }
    }
}

您会看到前两个参数(“test”和“testa”)无法解码,但第三个参数(“testaa”)会成功。

为了“修复”这个问题,将解码方法更改如下:

    private static string Decode(string htmlEncoded)
    {
        try
        {
            string regularEncodedString = WebUtility.UrlDecode(htmlEncoded);
            byte[] decoded = Convert.FromBase64String(regularEncodedString);

            return Encoding.ASCII.GetString(decoded);
        }
        catch(Exception)
        {
            return "Decoding failed";
        }
    }

【讨论】:

  • 有一个非常基本的假设,即解码的 Base64 是 ASCII 甚至是任何可打印的字符串。 Base64 通常用于将二进制编码为可打印的字符串表示形式。
  • "Base64 是一组类似的二进制到文本的编码方案,通过将二进制数据转换为 radix-64 表示,以 ASCII 字符串格式表示二进制数据。" en.wikipedia.org/wiki/Base64 我试图解释我将如何解决这样的问题并给出了一个可行的例子。我怎样才能改进我的答案?
  • 最简单的方法是显示 Base64 编码的数据并对其进行目视检查,并可能使用Base64 -> hexadecimal 等网站对其进行解码。无需编码。示例用法代码很好,但 Encoding.ASCII.GetString(decoded); 是一个可怕的示例,因为它不适用于 Base64 编码的非 ASCII 数据,这是 Base64 的常用用法。
【解决方案2】:

感谢您的所有回复。

原来仍然有一些 Json 格式的旧消息在我们的系统中传递失败并不断重试;但是,我们接收方的新代码更改已部署,并且我们的接收方开始期待 protobuf 格式的消息,这导致在接收旧的 Json 格式消息时反序列化失败。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-24
    相关资源
    最近更新 更多