问题
今天在开发的过程中,前端传过来的是base64的图片地址,如下所示:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2NjIpLCBxdWFsaXR5ID0gNzUK/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgBkAGQAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZ…1OSXJf3djzM2Nx/dekNpcD+Fvyr07+wrXPVqcPD9oepaqIaR5d9luP7jflThb3A6qw/CvUh4csz3al/wCEbtezNTsToeXrHN7/AJVZiEi4JB/KvSR4ZtT0dh+FSL4XtT/GfyppMTlFH//Z
因为图片地址过长,只展示部分图片地址。
后端接到base64的图片地址后,需要解析出改地址信息,当时考虑到使用的是commonsc-codec进行解密,但报出来如下的错误:
Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible value. Expected the discarded bits to be zero.
通过断点的方式,查询出报错信息的位置,如下所示。
分析问题
于是,到源码里面看报错信息的出处,原来问题出现在这里,commonsc-codec在升级之后,其内部做了一个validateCharacter校验,报出这样的错误。
/**
* Validates whether decoding the final trailing character is possible in the context
* of the set of possible base 64 values.
*
* <p>The character is valid if the lower bits within the provided mask are zero. This
* is used to test the final trailing base-64 digit is zero in the bits that will be discarded.
*
* @param emptyBitsMask The mask of the lower bits that should be empty
* @param context the context to be used
*
* @throws IllegalArgumentException if the bits being checked contain any non-zero value
*/
private static void validateCharacter(final int emptyBitsMask, final Context context) {
if ((context.ibitWorkArea & emptyBitsMask) != 0) {
throw new IllegalArgumentException(
"Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible value. " +
"Expected the discarded bits to be zero.");
}
}
这段代码是什么意思呢?翻译成中文:
验证在一组可能的 base 64 值的上下文中是否可以解码最后一个尾随字符。如果提供的掩码中的较低位为零,则该字符有效。这用于测试最终的尾随 base-64 数字在将被丢弃的位中是否为零。
通过翻译可以了解到该方法的作用,然后再分析这两个参数:
-
ibitWorkArea
: 位处理的基本位数 -
numBitsToDrop
: 应该为空的低位数目
可以看出当 context.ibitWorkArea & numBitsToDrop
不为0时就会抛出异常,实际上只有base64严格模式编码下,才可能会为0,松散模式不会为0
解决问题
方式一
commons-codec版本更新到1.15,最新的源码已经处理了该问题。
引入jar包
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
查看源码:
private void validateCharacter(final int emptyBitsMask, final Context context) {
if (isStrictDecoding() && (context.ibitWorkArea & emptyBitsMask) != 0) {
throw new IllegalArgumentException(
"Strict decoding: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible encoding. " +
"Expected the discarded bits from the character to be zero.");
}
}
方式二
可以使用谷歌的guava来替换common-codec来解密base64格式的文件
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
如下代码解析代码:
byte[] imageByte = BaseEncoding.base64().decode(imageString);
结果能正常解析。
扩展备注
base64的严格模式和松散模式定义,直接引用源码了
松散模式
任何尾随位都尽可能组合成 8 位字节。其余的被丢弃。
严格模式
严格模式: 如果尾随位,解码将引发 {@link IllegalArgumentException}不是有效编码的一部分。 最后一个字符中的任何未使用的位必须为零。 不允许对整个最终字符进行不可能计数。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99219.html