简体   繁体   English

如何在Base64中正确编码和解码字符串?

[英]How to correctly encode and decode a string in Base64?

I want to encode a string in Base64 for later decoding it. 我想在Base64中编码一个字符串,以便以后对其进行解码。 I encode it doing this: 我对此进行编码:

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

Then, the encoded string is stored on disk using UTF-8. 然后,使用UTF-8将编码后的字符串存储在磁盘上。 After restarting the application, the encoded string is readed from disk and I'm trying to decode the string using this: 重新启动应用程序后,将从磁盘读取编码后的字符串,而我正在尝试使用以下方法对该字符串进行解码:

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

Something is wrong because it is giving me this exception: 发生错误,因为它给了我这个例外:

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)

This is a TRACE step by step 这是一个循序渐进的步骤

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

into this: eyJjb25maWd1cmF0aW9uIjp7InNob3AiOnsibmFtZSI6IiIsImFkZHJlc3NMaW5lMSI6IiIsImFkZHJlc3NMaW5lMiI6IiIsInBvc3RhbENvZGUiOiIiLCJjaXR5IjoiIiwiY291bnRyeSI6IiIsInBob25lTnVtYmVyIjoiIn19LCJqb2ludEJldHMiOltdLCJncm91cHMiOlt7Im5hbWUiOiJUZXN0IiwibWVtYmVycyI6W119XX0= 成这样: eyJjb25maWd1cmF0aW9uIjp7InNob3AiOnsibmFtZSI6IiIsImFkZHJlc3NMaW5lMSI6IiIsImFkZHJlc3NMaW5lMiI6IiIsInBvc3RhbENvZGUiOiIiLCJjaXR5IjoiIiwiY291bnRyeSI6IiIsInBob25lTnVtYmVyIjoiIn19LCJqb2ludEJldHMiOltdLCJncm91cHMiOlt7Im5hbWUiOiJUZXN0IiwibWVtYmVycyI6W119XX0=

2º i store it on disk in utf8 2º我将其存储在utf8中的磁盘上

3º i retreive it from disk and it's this string: 3º我从磁盘撤回了它,它是这个字符串:

eyJjb25maWd1cmF0aW9uIjp7InNob3AiOnsibmFtZSI6IiIsImFkZHJlc3NMaW5lMSI6IiIsImFkZHJlc3NMaW5lMiI6IiIsInBvc3RhbENvZGUiOiIiLCJjaXR5IjoiIiwiY291bnRyeSI6IiIsInBob25lTnVtYmVyIjoiIn19LCJqb2ludEJldHMiOltdLCJncm91cHMiOlt7Im5hbWUiOiJUZXN0IiwibWVtYmVycyI6W119XX0=

4º i decode it and get the exception. 4º我将其解码并得到异常。

My guess is that you are not specifying a charset. 我的猜测是您没有指定字符集。 Try running the below maybe with and without the charset specified for the String constructor to verify. 尝试在没有为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);
    }

Then, the encoded string is stored on disk using UTF-8. 然后,使用UTF-8将编码后的字符串存储在磁盘上。 After restarting the application, the encoded string is readed from disk and I'm trying to decode the string using this: 重新启动应用程序后,将从磁盘读取编码后的字符串,而我正在尝试使用以下方法对该字符串进行解码:

This seems to be a point of failure. 这似乎是一个失败点。 Most likely your problem is OS/JDK dependent Apparently the following code seems to work well for me (Win 7, latest JDK 1.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 encoded: eyJjb25maWd1cmF0aW9uIjp7InNob3AiOnsibmFtZSI6IkVzcGHDsWEiLCJhZGRyZXNzTGluZTEiOiIiLCJhZGRyZXNzTGluZTIiOiIiLCJwb3N0YWxDb2RlIjoiIiwiY2l0eSI6IiIsImNvdW50cnkiOiIiLCJwaG9uZU51bWJlciI6IiJ9fSwiam9pbnRCZXRzIjpbXSwiZ3JvdXBzIjpbeyJuYW1lIjoiVGVzdCIsIm1lbWJlcnMiOltdfV19 Base64编码:eyJjb25maWd1cmF0aW9uIjp7InNob3AiOnsibmFtZSI6IkVzcGHDsWEiLCJhZGRyZXNzTGluZTEiOiIiLCJhZGRyZXNzTGluZTIiOiIiLCJwb3N0YWxDb2RlIjoiIiwiY2l0eSI6IiIsImNvdW50cnkiOiIiLCJwaG9uZU51bWJlciI6IiJ9fSwiam9pbnRCZXRzIjpbXSwiZ3JvdXBzIjpbeyJuYW1lIjoiVGVzdCIsIm1lbWJlcnMiOltdfV19

Base64 decoded: {"configuration":{"shop":{"name":"España","addressLine1":"","addressLine2":"","postalCode":"","city":"","country":"","phoneNumber":""}},"jointBets":[],"groups":[{"name":"Test","members":[]}]} 解码的Base64:{“ configuration”:{“ shop”:{“ name”:“España”,“ addressLine1”:“”,“ addressLine2”:“”,“ postalCode”:“”,“ city”:“”, “国家”: “”, “phoneNumber的”: “”}}, “jointBets”:[], “基团”:[{ “名称”: “测试”, “成员”:[]}]}

The old Base64 utility add linebreaks every 76 characters in Java8. 旧的Base64实用程序在Java8中每76个字符添加一个换行符。 The result looks like that: 结果看起来像这样:

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

It seems that this behaviour changed with some version. 似乎此行为在某些版本中已更改。 At least with Java11 the decoder is not accepting line-breaks anymore. 至少在Java11中,解码器不再接受换行符。 To avoid the problem you could change you method 为了避免出现问题,您可以更改方法

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM