【问题标题】:Base64 Encoding in Java vs HttpServerUtility.UrlTokenEncode in C#Java 中的 Base64 编码与 C# 中的 HttpServerUtility.UrlTokenEncode
【发布时间】:2019-03-29 17:10:44
【问题描述】:

我在尝试用 Java 编码 String 时遇到了问题。

我有以下 C# 代码,以及 string Bpz2Gjg01d7VfGfD8ZP1UA==,当我执行 C# 代码时,我得到:

QnB6MkdqZzAxZDdWZkdmRDhaUDFVQT090

public static void Main(string[] args)
{
    string strWord = "Bpz2Gjg01d7VfGfD8ZP1UA==";
    byte[] encbuff = Encoding.UTF8.GetBytes(strWord);
    string strWordEncoded = HttpServerUtility.UrlTokenEncode(encbuff);
    Console.WriteLine(strWordEncoded);
}

我试图在 Java 中复制以前的代码,在第一个 尝试我使用了javax.xml.bind.DatatypeConverterClass

public static void main(String[] args) {
    String strWord = "Bpz2Gjg01d7VfGfD8ZP1UA==";
    byte[] encbuff = strWord.getBytes(StandardCharsets.UTF_8);
    String strWordEncoded = DatatypeConverter.printBase64Binary(encbuff);
    System.out.println(strWordEncoded);
}

但我收到了以下String ( 与 C# 相比,缺少最后一个零 string):

QnB6MkdqZzAxZDdWZkdmRDhaUDFVQT09

在第二次尝试中,我使用了 BouncyCastle Base64 编码器:

public static void main(String[] args) {
   String strWord = "Bpz2Gjg01d7VfGfD8ZP1UA==";
   byte[] encbuff = strWord.getBytes(StandardCharsets.UTF_8);
   String strWordEncoded = new String(Base64.encode(encbuff));
   System.out.println(strWordEncoded);
}

但我得到了与之前完全相同的String( 仍然缺少最后一个零):

QnB6MkdqZzAxZDdWZkdmRDhaUDFVQT09

有人知道会发生什么吗?

【问题讨论】:

  • 您正在使用的 c# 方法可能正在使用 base64-url 编码。有多种 base64 编码类型,base64-url 编码不同于默认的 base64 编码。如果您想使用 base64 编码,请尝试 Java8 中的 Base64 形式的 java.util。
  • 另外,UrlTokenEncode 方法对来自常规 base64 编码的符号字符进行了一些映射,因此它们可以安全地用于 url,即它将 + 替换为 -/ 替换为_。如果您需要 Java 中的确切功能,则此映射也是必要的。但是,这不适用于您的情况。
  • 另外,如果您使用标准的 .NET Convert.ToBase64String(encbuff) 方法,它不会在末尾包含额外的 0,因此与 Java 等效项相同。看起来UrlTokenEncode 方法出于某种原因正在添加它。

标签: java c# base64 encode httpserverutility


【解决方案1】:

我查看了 .NET 框架代码。 UrlTokenEncode 实际上从 base64 字符串的末尾删除了任何额外的 = 填充符号,并将它们替换为填充符号的数量,因此可以是 012。这就是导致字符串末尾额外的0 的原因。所以请注意:HttpServerUtility.UrlTokenEncode 方法不是普通的 Base64 编码器。它实际上在内部使用Convert.ToBase64String 进行常规编码,并在顶部添加了更多内容(请参阅我的 cmets 问题)。如果您需要创建这个确切的字符串,您将需要在常规 base64 编码的基础上在 Java 中实现相同的更改。

【讨论】:

  • 非常感谢您的 cmets,他们充当了向导。
【解决方案2】:

根据给我做的cmets找到了解决方案,基本上我看Reference Source of Microsoft.中方法的源码

然后我将 C# 代码翻译成 Java 代码,它看起来像这样:

public static String UrlTokenEncode(byte[] input) {
     try {
         if (input == null) {
         return null;
         }

         if (input.length < 1) {
             return null;
         }

         String base64Str = null;
         int endPos = 0;
         char[] base64Chars = null;

         base64Str = Base64.toBase64String(input);
         if (base64Str == null) {
             return null;
         }

         for (endPos = base64Str.length(); endPos > 0; endPos--) {
             if (base64Str.charAt(endPos - 1) != '=') {
                 break;
             }
         }

         base64Chars = new char[endPos + 1];
         base64Chars[endPos] = (char) ((int) '0' + base64Str.length() - endPos);
         for (int iter = 0; iter < endPos; iter++) {
             char c = base64Str.charAt(iter);
              switch (c) {
                 case '+':
                     base64Chars[iter] = '-';
                     break;
                 case '/':
                     base64Chars[iter] = '_';
                     break;
                 case '=':
                     base64Chars[iter] = c;
                 break;
                 default:
                     base64Chars[iter] = c;
                 break;
             }
          }
         return new String(base64Chars);
     } catch (Exception e) {
         return null;
     }
}

最后我测试了方法,得到了期望的输出:

public static void main(String[] args) {
   String strWord = "Bpz2Gjg01d7VfGfD8ZP1UA==";
   byte[] encbuff = strWord.getBytes(StandardCharsets.UTF_8);
   String strWordEncoded = UrlTokenEncode(encbuff);
}

M2NIclh4eEwxRGp2MEsyeFc0SHVDZz090

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    • 2012-12-05
    • 2011-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多