【问题标题】:How to correctly encode and decode a string in Base64?如何正确编码和解码 Base64 中的字符串?
【发布时间】:2019-07-30 19:49:10
【问题描述】:

我想在 Base64 中对字符串进行编码,以便以后对其进行解码。我这样做编码它:

public static String encryptString(String string) {     
    byte[] bytesEncoded = Base64.getEncoder().encode(string.getBytes());
    return (new String(bytesEncoded));
}

然后,编码的字符串使用 UTF-8 存储在磁盘上。重新启动应用程序后,从磁盘读取编码字符串,我正在尝试使用以下方法解码字符串:

public static String decryptString(String string) {
    byte[] valueDecoded = Base64.getDecoder().decode(string);
    return (new String(valueDecoded));
}

出了点问题,因为它给了我这个例外:

java.lang.IllegalArgumentException: Illegal base64 character d
at java.base/java.util.Base64$Decoder.decode0(Base64.java:743)
at java.base/java.util.Base64$Decoder.decode(Base64.java:535)
at java.base/java.util.Base64$Decoder.decode(Base64.java:558)

这是一步一步的TRACE

1º 我对此进行编码:{"configuration":{"shop":{"name":"","addressLine1":"","addressLine2":"","postalCode":"","city":"","country":"","phoneNumber":""}},"jointBets":[],"groups":[{"name":"Test","members":[]}]}

进入这个:eyJjb25maWd1cmF0aW9uIjp7InNob3AiOnsibmFtZSI6IiIsImFkZHJlc3NMaW5lMSI6IiIsImFkZHJlc3NMaW5lMiI6IiIsInBvc3RhbENvZGUiOiIiLCJjaXR5IjoiIiwiY291bnRyeSI6IiIsInBob25lTnVtYmVyIjoiIn19LCJqb2ludEJldHMiOltdLCJncm91cHMiOlt7Im5hbWUiOiJUZXN0IiwibWVtYmVycyI6W119XX0=

2º 我将它以 utf8 格式存储在磁盘上

3º 我从磁盘中检索它,它是这个字符串:

eyJjb25maWd1cmF0aW9uIjp7InNob3AiOnsibmFtZSI6IiIsImFkZHJlc3NMaW5lMSI6IiIsImFkZHJlc3NMaW5lMiI6IiIsInBvc3RhbENvZGUiOiIiLCJjaXR5IjoiIiwiY291bnRyeSI6IiIsInBob25lTnVtYmVyIjoiIn19LCJqb2ludEJldHMiOltdLCJncm91cHMiOlt7Im5hbWUiOiJUZXN0IiwibWVtYmVycyI6W119XX0=

4º 我解码它并得到异常。

【问题讨论】:

  • 你为什么不encodeToString?但试过你的代码(jshell)工作正常
  • getBytes() 可能是个问题,因为它使用系统的本地默认字符集。在不同的系统上可能会有所不同。
  • Base64 Encoding in Java的可能重复
  • Base64.getMimeEncoder() ...getMimeDecoder()(或/和更改从磁盘写入/读取的方式)
  • 而不是 Base64.getEncoder() 你写 Base64.getMimeEncoder() - 这些忽略无效字符:"MIME ...所有行分隔符或其他在 base64 中找不到的字符解码操作中忽略字母表"

标签: java base64 decode encode


【解决方案1】:

我的猜测是您没有指定字符集。尝试运行以下命令,无论是否为 String 构造函数指定的字符集进行验证。

   @Test
    public void base64Test() throws Exception{
        String string = "ABCDF";

        byte[] bytesEncoded = Base64.getEncoder().encode(string.getBytes());
        String encodedStr = (new String(bytesEncoded,Charset.forName("ISO-8859-1")));
        System.out.println(encodedStr);

        byte[] valueDecoded = Base64.getDecoder().decode(encodedStr);
        String decodedStr = (new String(valueDecoded,Charset.forName("ISO-8859-1")));
        System.out.println(decodedStr);
    }

【讨论】:

  • 第一部分正是 encodeToString 所做的(如上面评论/建议/询问)
【解决方案2】:

然后,编码后的字符串使用 UTF-8 存储在磁盘上。后 重新启动应用程序,从磁盘读取编码字符串并 我正在尝试使用以下方法解码字符串:

这似乎是一个失败点。您的问题很可能与 OS/JDK 相关显然,以下代码对我来说似乎很有效(Win 7,最新的 JDK 1.8):

public static void main(String[] args) throws IOException {
    String source = "{\"configuration\":{\"shop\":{\"name\":\"España\",\"addressLine1\":\"\",\"addressLine2\":\"\"," +
                "\"postalCode\":\"\",\"city\":\"\",\"country\":\"\",\"phoneNumber\":\"\"}},\"jointBets\":[]," +
                "\"groups\":[{\"name\":\"Test\",\"members\":[]}]}";

    // Encode string
    String encoded = encryptString(source);

    System.out.println("Base64 encoded: " + encoded);

    // Temp Dir
    String tempDir = System.getProperty("java.io.tmpdir");

    // Write to File
    try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempDir + "data.txt"))) {
        writer.write(encoded);
    }

    // Read from File
    Path path = Paths.get(tempDir + "data.txt");

    Stream<String> lines = Files.lines(path);
    String dataFromFile = lines.collect(Collectors.joining("\n"));
    lines.close();

    // Compare content
    assert encoded.equals(dataFromFile);

    // Decode string
    String decoded = decryptString(dataFromFile);
    System.out.println("Base64 decoded: " + decoded);
}

public static String encryptString(String string) {
    byte[] bytesEncoded = Base64.getEncoder().encode(string.getBytes(StandardCharsets.UTF_8));
    return new String(bytesEncoded);
}

public static String decryptString(String string) {
    byte[] valueDecoded = Base64.getDecoder().decode(string);
    return new String(valueDecoded);
}

Base64 编码: eyJjb25maWd1cmF0aW9uIjp7InNob3AiOnsibmFtZSI6IkVzcGHDsWEiLCJhZGRyZXNzTGluZTEiOiIiLCJhZGRyZXNzTGluZTIiOiIiLCJwb3N0YWxDb2RlIjoiIiwiY2l0eSI6IiIsImNvdW50cnkiOiIiLCJwaG9uZU51bWJlciI6IiJ9fSwiam9pbnRCZXRzIjpbXSwiZ3JvdXBzIjpbeyJuYW1lIjoiVGVzdCIsIm1lbWJlcnMiOltdfV19 P>

Base64 解码: {"configuration":{"shop":{"name":"España","addressLine1":"","addressLine2":"","postalCode":"","city":"","country" :"","phoneNumber":""}},"jointBets":[],"groups":[{"name":"Test","members":[]}]}

【讨论】:

  • 他的问题是读取可能在文本末尾的回车符(代码 d),这在普通 base64 中是不允许的
【解决方案3】:

旧的 Base64 实用程序在 Java8 中每 76 个字符添加换行符。 结果如下所示:

/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIA
AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
...

似乎这种行为随着某些版本而改变。至少对于 Java11,解码器不再接受换行符。 为了避免这个问题,你可以改变你的方法

public static String decryptString(String string) {
    byte[] valueDecoded = Base64.getDecoder().decode(string.replace("\n","").replace("\r","");
    return new String(valueDecoded);
}

【讨论】:

  • 我使用了base64 -w 0,尽管没有换行符,但我仍然收到该错误。只有将 Base64.getDecoder() 更改为 Base64.getMimeDecoder() 有帮助,我真的不知道为什么。
猜你喜欢
  • 2021-10-27
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多