Wildfly: org.xnio.channels.FixedLengthOverflowException



到目前为止,我们使用的是JBoss AS 7.1,它的前端服务器是tomcat。我们现在升级到Wildfly (JBoss 8.0),它与undertow一起发布,作为tomcat的替代品。

对于filedownloads,我们读取文件的输入流,并将其写入外部上下文的响应输出流。这在JBoss AS 7.1中工作得很好——即使对于大文件也是如此。在Undertow中,即使对于非常"小"的文件,我们也会收到以下异常:

13:04:43,292 ERROR [io.undertow.request] (default task-15) Blocking request failed HttpServerExchange{ GET /project/getFile.xhtml}: java.lang.RuntimeException: org.xnio.channels.FixedLengthOverflowException
    at io.undertow.servlet.spec.HttpServletResponseImpl.responseDone(HttpServletResponseImpl.java:527)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:287)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_51]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_51]
    at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_51]
Caused by: org.xnio.channels.FixedLengthOverflowException
    at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.write(AbstractFixedLengthStreamSinkConduit.java:97)
    at org.xnio.conduits.Conduits.writeFinalBasic(Conduits.java:132) [xnio-api-3.2.0.Final.jar:3.2.0.Final]
    at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.writeFinal(AbstractFixedLengthStreamSinkConduit.java:137)
    at org.xnio.conduits.ConduitStreamSinkChannel.writeFinal(ConduitStreamSinkChannel.java:104) [xnio-api-3.2.0.Final.jar:3.2.0.Final]
    at io.undertow.channels.DetachableStreamSinkChannel.writeFinal(DetachableStreamSinkChannel.java:172)
    at io.undertow.servlet.spec.ServletOutputStreamImpl.writeBufferBlocking(ServletOutputStreamImpl.java:580)
    at io.undertow.servlet.spec.ServletOutputStreamImpl.close(ServletOutputStreamImpl.java:614)
    at io.undertow.servlet.spec.HttpServletResponseImpl.closeStreamAndWriter(HttpServletResponseImpl.java:451)
    at io.undertow.servlet.spec.HttpServletResponseImpl.responseDone(HttpServletResponseImpl.java:525)
    ... 9 more

getFile.xhtml正在调用下载,下面的代码用于复制流:

(删除Try, catch,日志和错误处理以节省空间)

public void downloadFile(FileEntity fileEntity) {
        FacesContext fc = FacesContext.getCurrentInstance();
        ExternalContext ec = fc.getExternalContext();
        ec.responseReset();
        ec.setResponseContentType(getMimeType(fileEntity.getFile()));
        ec.setResponseContentLength(new Long(fileEntity.getFile().length()).intValue());
        ec.setResponseHeader("Content-Disposition", "attachment; filename="" + ConversionHelper.validateFilename(fileEntity.getDisplayFileName()) + """);
        OutputStream output = ec.getResponseOutputStream();
        FileInputStream fis = new FileInputStream(fileEntity.getFile());
        IOUtils.copy(fis, output);
        fc.responseComplete();
    }
我注意到删除 一行
ec.setResponseContentLength(new Long(fileEntity.getFile().length()).intValue());

使它再次工作。然而,ResponseConentLength是"正确的"。使用

ec.setResponseContentLength(new Long(fileEntity.getFile().length()).intValue() + 9);

(注意+9)解决了这个问题。使用+8 -> FixedLengthOverflow,使用+10 -> FixedLengthUnderflow

+9与文件大小无关。任何想法?

如果您调用output.close(),它应该有您想要的效果。这看起来像是JSF的问题,而与Undertow无关。

找到问题了

这与服务器引擎的变化有关。只是不确定它是否与undertow直接相关,或者更多的是wildfly/JSF的错误(或者如果它是Jboss中的错误,现在工作正常):

为了调用下载,我们在getFile.xhtml:

中使用了如下代码
    <f:metadata>
        <f:viewParam name="fileId" required="true"
            value="#{getFileController.fileId}"></f:viewParam>
    </f:metadata>
    <h:outputLabel value="#{getFileController.download()}" />

通常会产生:

<label>value</label>
如果标签的值是字符串,则使用

由于我们重置了download()内部的响应,因此<label>再次被删除。然后,使用与文件长度相等的固定响应大小并调用responseComplete()基本上会提交末尾的</label>。然而,Undertow似乎忽略了responseComplete() -Call,并试图将</label>附加到响应中,注意到(固定)响应流的末端已经到达,因此抛出上述异常。

这就是为什么提供+9的大小解决了这个错误-但会导致损坏的文件,因为</label>n将追加到文件。

显然在这里使用输出标签是不好的做法。但由于我们重置并手动填充响应流并调用responseComplete(),因此工作正常。

修复显然是不产生任何(不需要的)HTML标签在该页上:

    <f:metadata>
        <f:viewParam name="fileId" required="true"
            value="#{getFileController.fileId}"></f:viewParam>
        <f:event listener="#{getFileController.dlNow()}" type="preRenderView"></f:event>
    </f:metadata>

除了糟糕的设计之外-不应该调用responseComplete()向响应流提交任何额外的写入,包括任何写尝试?

文档说:

通知HTTP响应的JavaServer Faces实现此请求已经生成(例如HTTP重定向),并且请求处理生命周期应该尽快终止当当前阶段完成时

所以,如果Faces Implementation 被告知响应已经发送-为什么它会尝试附加一些东西?

相关内容

  • 没有找到相关文章

最新更新