You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tomcat8/9下BitmapFactory.decodeByteArray解码图片字节数组返回null问题

看起来你遇到了一个典型的WebSocket图片传输在Tomcat独立环境下的兼容性问题,我帮你分析下根源和解决方案:

问题核心根源

你之前用Tomcat Maven插件正常,切换到独立Tomcat(7/8/9)后BitmapFactory.decodeByteArray返回null,本质是服务器端的ByteBuffer处理逻辑有隐藏bug,Tomcat独立版本的多线程/缓冲区管理机制让这些bug暴露了出来:

1. ByteBuffer的position未重置

当你多次调用bbuf.put(msg)后,ByteBuffer的position会指向最后写入的位置,此时直接把bbuf传给sendBuf,发送的是position到limit之间的空填充数据(因为你预分配了1MB缓冲区,没填满的部分都是0)。客户端收到的字节数组包含大量无效字节,自然无法被BitmapFactory解析。

2. 消息长度统计错误

你用msg.array().length累加图片大小是错误的——ByteBuffer.array()返回的是整个底层数组(可能远大于当前消息的实际有效长度),正确的做法是用msg.remaining()获取当前消息的真实字节数。

3. 成员变量ByteBuffer的线程安全问题

bbuf作为类成员变量,多个客户端同时上传图片时会互相覆盖字节流,这在Tomcat多线程环境下必然导致数据混乱。

修复后的服务器端代码

我重新调整了服务器端的WebSocket处理逻辑,解决了上述所有问题:

@OnMessage
public void processUpload(ByteBuffer msg, boolean last, Session session) {
    // 每个会话单独维护上传缓冲区,避免多线程冲突
    ByteArrayOutputStream baos = (ByteArrayOutputStream) session.getUserProperties().get("uploadBaos");
    if (baos == null) {
        baos = new ByteArrayOutputStream();
        session.getUserProperties().put("uploadBaos", baos);
    }

    // 提取当前消息的有效字节
    byte[] chunk = new byte[msg.remaining()];
    msg.get(chunk);
    
    try {
        baos.write(chunk);
    } catch (IOException e) {
        e.printStackTrace();
        // 异常时清理资源并中断上传
        session.getUserProperties().remove("uploadBaos");
        return;
    }

    if (last) {
        byte[] imageBytes = baos.toByteArray();
        System.err.println("Final Image Size : " + imageBytes.length);
        // 发送完整的图片字节数组
        sendBuf(imageBytes);

        // 清理会话临时资源
        try {
            baos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        session.getUserProperties().remove("uploadBaos");
    }
}
额外验证与优化建议
  1. 客户端验证字节流有效性
    在客户端添加日志,确认收到的字节流是否是合法的图片格式(比如JPEG的前两个字节是0xFF 0xD8):
byte [] ar = message.getImageMessage().getByteArray();
Log.d("ImageDebug", "Received bytes length: " + ar.length);
// 打印图片头信息
if (ar.length >= 2) {
    Log.d("ImageDebug", "Image header: " + String.format("%02X %02X", ar[0], ar[1]));
}
Bitmap bmp = BitmapFactory.decodeByteArray(ar , 0, ar.length);

如果头不是FF D8,说明服务器端的字节流确实损坏了。

  1. 调整Tomcat WebSocket缓冲区配置
    在server.xml的Connector中添加WebSocket缓冲区大小配置,避免大图片被截断:
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           maxBinaryMessageBufferSize="1048576"/> <!-- 1MB,可根据你的图片大小调整 -->
  1. 客户端简化冗余代码
    你客户端里的bmp.compress步骤是多余的,直接用原始解析的Bitmap即可,不需要重新压缩。
为什么Tomcat Maven插件之前正常?

Tomcat Maven插件的默认配置更宽松,且通常是单线程调试模式,刚好掩盖了ByteBuffer的position问题和线程安全问题。而独立Tomcat的多线程生产环境让这些隐藏bug直接显现了出来。

内容的提问来源于stack exchange,提问作者Макс Туровец

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:46:02