目录
[工具类,做好异常log。能跑不代表就没问题!下面分享一个最近遇到的线上问题]
base64转PNG
下面是一个将图片的base64 字符串 转换成图片输出到客户端的工具类代码
private void getImage(String base64Str, HttpServletResponse response) {
byte[] base64 = Base64.decode(base64Str);
ByteArrayInputStream arrayInputStream = null;
try {
arrayInputStream = new ByteArrayInputStream(base64);
BufferedImage img = ImageIO.read(arrayInputStream);
ImageIO.write(img, "png", response.getOutputStream());
} catch (Exception ex) {
ex.printStackTrace();
}
}
这个代码编译运行均没问题。可在线上环境运行1个月的时间,出现了3次error的情况。
案例分析
报错信息
java.lang.IndexOutOfBoundsException: null
at javax.imageio.stream.FileCacheImageOutputStream.seek(FileCacheImageOutputStream.java:170)
at javax.imageio.stream.FileCacheImageOutputStream.close(FileCacheImageOutputStream.java:231)
at javax.imageio.ImageIO.write(ImageIO.java:1580)
最后找到了ORACLE的官网,看到了该Bug的描述。首先,该Bug是偶现的。其次该Bug主要是由于,flushedPos设置为缓存文件末尾的4字节,这会导致在刷新流时发生异常,因为“pos”是文件的实际结尾,并且位于“flushedPos”之前。
After some investigation, I've found that in javax.imageio.stream.FileCacheImageOutputStream.seek(), flushedPos is set to 4 bytes past the end of the cache file, which causes the exception when the stream is flushed since 'pos' is the actual end of the file, and is before the 'flushedPos'.
This bug does not always happen. In 20 draws it would occur anywhere from 3-7 times. (It's a mapping application, and the draws are map tiles.)
解决方法
接着按照jdk提供的替代方案解决,代码修改如下
ImageIO.write(img, "png", new MemoryCacheImageOutputStream(response.getOutputStream()));
资料参考
[1] : https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6967419
[2] : https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8041746