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

Hessian远程服务InputStream流关闭异常问题求助

解决Hessian远程调用中InputStream读取时"stream is closed"异常

这个问题的核心原因是Hessian与Spring的默认封装机制导致HTTP连接提前关闭:当你通过Spring的HessianServiceExporter返回InputStream时,Hessian并不会将流的内容完整序列化到响应中,而是仅传递一个"引用";但Spring会在请求处理完成后立即关闭HTTP响应流,此时客户端还没来得及读取流内容,就会触发stream is closed异常。

Hessian官网提到的"自行处理流",本质是让你避免直接返回InputStream,或者手动控制Hessian的流传输逻辑,下面提供两种可行方案:

方案一:转成byte[]传输(简单通用,适合中小数据量)

这是最直接的解决方式,把服务端的流内容提前转为字节数组,让Hessian完整序列化整个数组,客户端拿到的是完整数据,不依赖HTTP连接存活。

修改服务接口与实现

// 服务接口:将返回值改为byte[]
public interface EchoService {
    byte[] echo(String text);
}

// 服务实现:直接返回字节数组,无需InputStream
public class EchoServiceImpl implements EchoService {
    @Override
    public byte[] echo(String text) {
        System.out.println("Echo on server " + text);
        return text.getBytes();
    }
}

修改客户端代码

import com.caucho.hessian.client.HessianProxyFactory;

public class Client {
    public static void main(String[] args) throws Exception {
        HessianProxyFactory factory = new HessianProxyFactory();
        EchoService service = (EchoService) factory.create(EchoService.class, "http://localhost:8080/repeat");
        // 直接获取byte[],无需处理流
        byte[] responseData = service.echo(args[0]);
        System.out.println(new String(responseData));
    }
}

这个方案完全兼容Spring的HessianServiceExporter,不需要额外配置,解决了连接提前关闭的问题。

方案二:使用Hessian Streaming API(适合大数据量,避免内存溢出)

如果数据量极大,无法一次性转为byte[],可以使用Hessian原生的流式API,手动控制请求与响应的流传输,脱离Spring的自动封装。

服务端自定义Controller(替代HessianServiceExporter)

import com.caucho.hessian.server.HessianSkeleton;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

@RestController
public class HessianStreamController {
    // 手动创建Hessian骨架,绑定服务接口与实现
    private final HessianSkeleton skeleton = new HessianSkeleton(EchoStreamService.class, new EchoStreamServiceImpl());

    @PostMapping("/repeat-stream")
    public void handleStreamRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType("application/x-hessian");
        // 直接操作Hessian的输入输出流,避免Spring提前关闭连接
        skeleton.invoke(request.getInputStream(), response.getOutputStream());
    }

    // 保持原接口的InputStream返回值
    public interface EchoStreamService {
        InputStream echo(String text);
    }

    public static class EchoStreamServiceImpl implements EchoStreamService {
        @Override
        public InputStream echo(String text) {
            System.out.println("Echo on server " + text);
            return new ByteArrayInputStream(text.getBytes());
        }
    }
}

客户端手动处理流式调用

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.google.common.io.ByteStreams;

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class StreamClient {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://localhost:8080/repeat-stream");
        URLConnection conn = url.openConnection();
        conn.setDoOutput(true);
        conn.setRequestProperty("Content-Type", "application/x-hessian");

        // 手动写入Hessian请求:调用echo方法并传递参数
        Hessian2Output out = new Hessian2Output(conn.getOutputStream());
        out.startCall("echo");
        out.writeString(args[0]);
        out.completeCall();
        out.close();

        // 手动读取Hessian响应:用readInputStream获取流,确保连接在读取完成后才关闭
        Hessian2Input in = new Hessian2Input(conn.getInputStream());
        in.startReply();
        try (InputStream is = in.readInputStream()) {
            byte[] data = ByteStreams.toByteArray(is);
            System.out.println(new String(data));
        }
        in.completeReply();
        in.close();
    }
}

这种方式直接操作Hessian的底层流,让服务端和客户端共同维护流的生命周期,不会出现提前关闭的问题,适合处理GB级别的大文件或数据流。

关键注意事项

  • 若使用方案一,需注意数据大小:过大的byte[]会导致JVM内存溢出,此时必须切换到方案二。
  • 保持服务端与客户端的Hessian版本一致(你当前使用的4.0.51版本没问题),避免序列化/反序列化兼容性问题。

内容的提问来源于stack exchange,提问作者willix

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:01:36