在Spring-MVC中使用ResponseBodyEmitter进行HTTP Streaming时出现IllegalStateException

时间:2015-07-03 02:43:52

标签: java spring spring-mvc exception exception-handling

我在Spring 4.2.0.BUILD-SNAPSHOT中使用了新增的HTTP Streaming功能和ResponseBodyEmitter。

我想在(可能是java)客户端和服务器之间的不可用数据流上实现长时间运行的持久TCP连接,直到客户端断开连接。我想避免使用websocket协议。

  1. 如果客户端在流式传输时断开连接,则抛出运行时IllegalStateException。我想优雅地处理这个并清理发射器。没有捕获运行时异常,有没有办法优雅地处理它?<​​/ li>
  2. 我必须在发射器上为&#34; persistent&#34;指定一个人为高的超时值。连接。我可以设置暂停吗?
  3. webapp部署在apache-tomcat-7.0.62上。

    相关代码如下:

        while (true) {
            for (Iterator<ResponseBodyEmitter> iterator = emitters.iterator(); iterator.hasNext();) {
                ResponseBodyEmitter emitter = iterator.next();
                try {
                    emitter.send("data...", MediaType.TEXT_PLAIN);
                } catch (IOException | IllegalStateException e) {
                    LOGGER.error(e);
                    iterator.remove();
                }
            }
    
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                LOGGER.error(e);
            }
        }
    

    INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately
    java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
        at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215)
        at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480)
        at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:119)
        at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:801)
        at org.apache.coyote.Response.action(Response.java:172)
        at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:363)
        at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:331)
        at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:101)
        at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:297)
        at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
        at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
        at org.springframework.util.StreamUtils.copy(StreamUtils.java:106)
        at org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:109)
        at org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:40)
        at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:193)
        at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler$HttpMessageConvertingHandler.sendInternal(ResponseBodyEmitterReturnValueHandler.java:157)
        at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler$HttpMessageConvertingHandler.send(ResponseBodyEmitterReturnValueHandler.java:150)
        at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.sendInternal(ResponseBodyEmitter.java:180)
        at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.send(ResponseBodyEmitter.java:164)
        ....
    
    [ERROR] [02/07/15 18:11 PM] [Controller$TestResponseBodyEmitter:74] - java.lang.IllegalStateException: The request associated with the AsyncContext has already completed processing.
    

    日志:

    curl http://localhost:8080/myapp/stream -v -N
    data...data...
    Ctrl-C
    

    命令:

    NewObject

1 个答案:

答案 0 :(得分:0)

根据ResponseBodyEmitter的构造函数的Javadoc(找到here)。

  

使用自定义超时值创建ResponseBodyEmitter。默认情况下   不设置在MVC Java Config中配置的默认值   使用MVC命名空间,或者如果未设置,则超时   取决于底层服务器的默认值。

因此,在创建c实例时,会发出超时。

PS:在我的环境中,ResponseBodyEmitter#getTimeout()返回null;这并不意味着存在无限超时。相反,5-10秒后连接超时。