首页 > 解决方案 > Java 中由 Base64 和 RFC2047 编码的解码字符串(来自标头)

问题描述

我正在开发一个函数来解码在 Java 中以 Base64 和 RFC2047 编码的字符串(来自标头)。

鉴于此标头:

SGVhZGVyOiBoZWFkZXJ2YWx1ZQ0KQmFkOiBOYW1lOiBiYWRuYW1ldmFsdWUNClVuaWNvZGU6ID0/VVRGLTg/Qj81YmV4NXF5eTU2dUw2SUNNNTZ1TDVMcTY3N3lNNWJleDVxeXk2WUdVNklDTTZZR1U/PSA9P1VURi04P0I/NUxxNjc3eU01YmV4NW9tQTVMaU41cXl5Nzd5TTVZdS81cGE5NXBhODVMcTY0NENDPz0NCg0K

我的预期输出是:

Header: headervalue Bad: Name: badnamevalue Unicode: 己欲立而立人,己欲达而达人,己所不欲,勿施于人。</p>

我找到并尝试过的唯一相关功能是Base64.decodeBase64(headers),它在打印出来时会产生这个:

标头:headervalue 错误:名称:badnamevalue Unicode:=?UTF-8?B?5bex5qyy56uL6ICM56uL5Lq677yM5bex5qyy6YGU6ICM6YGU?= =?UTF-8?B?5Lq677yM5bex5omA5LiN5qyy77yM5Yu/5pa95pa85Lq644CC?=

为了解决这个问题,我一直在尝试通过将返回的字节数组转换Base64.decodeBase64(headers)为 InputStream 来尝试 MimeUtility.decode(),但结果与上面相同。

InputStream headerStream = new ByteArrayInputStream(Base64.decodeBase64(headers));
InputStream result = MimeUtility.decode(headerStream, "quoted-printable");

一直在互联网上搜索,但尚未找到解决方案,想知道是否有人知道从结果字节数组中解码 MIME 标头的方法?

任何帮助表示赞赏!这也是我的第一个堆栈溢出帖子,如果我遗漏了什么,请道歉,但如果我可以提供更多信息,请告诉我!

标签: javaencodingutf-8base64decoding

解决方案


你在那里的base64实际上就是你粘贴的。包括奇怪的 =?UTF-8?B? 怪异。

接下来的东西是base64。

您的 base-64 编码数据中有 base64 编码数据。正如 Xzibit 所说:我在你的 base64 中加入了一些 Base64,这样你就可以在使用 base64 的同时使用 base64。为什么我突然觉得老了?

换句话说,你得到的base64输入是一个疯狂的人发明的一种疯狂的、效率极低的格式。

我的建议是你告诉他们想出一些不那么疯狂的东西。

做不到这一点:

在结果字符串中搜索正则表达式模式,然后再次将 base64 解码应用于中间的内容。

此外,您正在使用一些第三方 base64 解码器,可能是 apache。Apache 库往往很糟糕。Base64 被嵌入到 java 中,这里没有理由使用更差的库。我已经解决了;此代码段中的 Base64 是java.util.Base64. 它的 API 略有不同。

String sourceB64 = "SGV..."; // that input base64 you have.
byte[] sourceBytes = Base64.decodeBase64(sourceB64);
String source = new String(sourceBytes, StandardCharsets.UTF_8);
Pattern p = Pattern.compile("=\\?UTF-8\\?B\\?(.*?)\\?=");
Matcher m = p.matcher(source);
StringBuilder out = new StringBuilder();
int curPos = 0;
while (m.find()) {
  out.append(source.substring(curPos, m.start()));
  curPos = m.end();
  String content = new String(Base64.getDecoder().decode(m.group(1)), StandardCharsets.UTF_8);
  out.append(content);
}
out.append(source.substring(curPos));

System.out.println(out.toString());

如果我运行它,我会得到:

Header: headervalue
Bad: Name: badnamevalue
Unicode: 己欲立而立人,己欲達而達 人,己所不欲,勿施於人。

这看起来完全像你想要的。

该代码的解释:

  • 它首先对输入进行 base64 解码,然后将其转换为字符串。(您使用 InputStream 的想法是一个红鲱鱼。这在这里根本没有帮助。您只想将字节转换为字符串,您按照该片段的第 3 行进行操作。传递字节数组和编码这些字节在,这就是你需要做的)。
  • =?UTF-8?B?--base64here--?=然后它继续在你的 base64 内部寻找。base64-in-the-base64。
  • 然后它解码那个base64,以同样的方式把它变成一个字符串,然后替换它。
  • 它只是=?UTF-8?B?...?=逐字添加这些片段之外的所有内容。

推荐阅读