【问题标题】:Download accelerator causes org.apache.catalina.connector.ClientAbortException: java.io.IOException when providing download from backing bean下载加速器导致 org.apache.catalina.connector.ClientAbortException: java.io.IOException 在从支持 bean 提供下载时
【发布时间】:2015-10-16 12:29:31
【问题描述】:

我使用 JSF 并希望在我的页面中下载文件。我写了一些代码,但是当我使用一些下载管理器下载我的文件时出现 ClientAbortException 错误:

public class FileUtil  {


public static FacesContext getContext() {
    return FacesContext.getCurrentInstance();
}

public static void sendFile(File file, boolean attachment) throws IOException {
    sendFile(getContext(), file, attachment);
}

public static void sendFile(FacesContext context, File file, boolean attachment) throws IOException {
    sendFile(context, new FileInputStream(file), file.getName(), file.length(), attachment);
}

public static void sendFile(FacesContext context, byte[] content, String filename, boolean attachment) throws IOException {
    sendFile(context, new ByteArrayInputStream(content), filename, (long) content.length, attachment);
}

public static void sendFile(FacesContext context, InputStream content, String filename, boolean attachment) throws IOException {
    sendFile(context, content, filename, -1L, attachment);
}

private static void sendFile(FacesContext context, InputStream input, String filename, long contentLength, boolean attachment) throws IOException {
    ExternalContext externalContext = context.getExternalContext();
    externalContext.setResponseBufferSize(10240);
    externalContext.setResponseContentType(getMimeType(context, filename));
    externalContext.setResponseHeader("Content-Disposition", String.format("%s;filename=\"%2$s\"; filename*=UTF-8\'\'%2$s", new Object[]{attachment ? "attachment" : "inline", encodeURL(filename)}));
    if (((HttpServletRequest) externalContext.getRequest()).isSecure()) {
        externalContext.setResponseHeader("Cache-Control", "public");
        externalContext.setResponseHeader("Pragma", "public");
    }

    if (contentLength != -1L) {
        externalContext.setResponseHeader("Content-Length", String.valueOf(contentLength));
    }

    long size = stream(input, externalContext.getResponseOutputStream());
    if (contentLength == -1L) {
        externalContext.setResponseHeader("Content-Length", String.valueOf(size));
    }

    context.responseComplete();
}


public static String getMimeType(FacesContext context, String name) {
    String mimeType = context.getExternalContext().getMimeType(name);
    if (mimeType == null) {
        mimeType = "application/octet-stream";
    }

    return mimeType;
}

public static long stream(InputStream input, OutputStream output) throws IOException {



    ReadableByteChannel inputChannel = Channels.newChannel(input);
    Throwable var3 = null;

    try {
        WritableByteChannel outputChannel = Channels.newChannel(output);
        Throwable var5 = null;

        try {
            ByteBuffer buffer = ByteBuffer.allocateDirect(10240);
            long size = 0L;

            while (inputChannel.read(buffer) != -1) {
                buffer.flip();
                size += (long) outputChannel.write(buffer);
                buffer.clear();
            }

            long var9 = size;
            return var9;
        } catch (Throwable var33) {
            var5 = var33;
            throw var33;
        } finally {
            if (outputChannel != null) {
                if (var5 != null) {
                    try {
                        outputChannel.close();
                    } catch (Throwable var32) {
                        var5.addSuppressed(var32);
                    }
                } else {
                    outputChannel.close();
                }
            }

        }
    } catch (Throwable var35) {
        var3 = var35;
        throw var35;
    } finally {
        if (inputChannel != null) {
            if (var3 != null) {
                try {
                    inputChannel.close();
                } catch (Throwable var31) {
                    var3.addSuppressed(var31);
                }
            } else {
                inputChannel.close();
            }
        }

    }

}

public static String encodeURL(String string) {
    if (string == null) {
        return null;
    } else {
        try {
            return URLEncoder.encode(string, StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException var2) {
            throw new UnsupportedOperationException("UTF-8 is apparently not supported on this platform.", var2);
        }
    }
}

}

我无法理解的是,当通过本机 chorome 下载完成下载而不使用任何下载管理器(如 IDM 或 eagleget)时,我没有收到任何 ClientAbortException,但是当我使用这些下载管理器软件时(启用他们的插件)我收到这些错误

会发生什么?我知道这个错误是由于某些连接丢失而发生的......但我没有关闭我的页面或任何导致此错误的事情! 这是我的 bean 代码:

@ManagedBean(name = "bean")
@RequestScoped
public class MB implements Serializable {

public void MBdowan() throws IOException {


    File file = new File("E:\\Animation\\IA\\Learning movies\\webinar1\\01_Aug_webinar_08\\Aug08_edited_webinar_animation.mov");

    FileUtil.sendFile(file,true);

}

这是我的 xhtml 页面:

</h:head>
<h:body>
    <h:form>
        <p:commandButton value="Download file" ajax="false" actionListener="#{bean.MBdowan}"/>
    </h:form>
</h:body>

【问题讨论】:

  • 下载管理器通常期望幂等可用的文件(即通过 GET 而不仅仅是通过 POST 可用的文件),最有可能最好还有 HEAD 支持。如果不知道确切的管理器和实际的 HTTP 流量,很难回答。一般来说,你最好的选择是像这样的文件 servlet snapshot.omnifaces.org/servlets/FileServlet
  • 感谢 BalusC,我使用 EagleGet 和 Download Accelerator Plus,你的 post 或 get 到底是什么意思……我正在使用 JSF externalContext.getResponseOutputStream() !!!
  • 不需要用感叹号抛出。它只是 HTTP 动词。或许您最好暂停一下 JSF,先学习基本的 HTTP。尽管如此,我还是发布了一个答案。
  • 好的……谢谢伙计……你能不能提供一些参考以更好地理解HTTP

标签: file jsf jsf-2 primefaces download


【解决方案1】:

下载加速器(和媒体播放器!)期望文件可以通过 GET 和 HEAD 请求(即,仅在浏览器的地址栏中键入 URL 时)幂等地可用,并且最好还支持 HTTP Range 请求(因此可以打开多个 HTTP 连接同时下载零件)。 JSF 支持 bean 方法仅在 POST 请求上调用(即,当提交带有 method="post" 的 HTML 表单时)。 ClientAbortException 发生是因为下载加速器在嗅探 HEAD 和 Range 支持时没有得到预期的响应并中止它。

如果这些文件是静态的,因此不是动态的,那么最好的办法是创建一个单独的 servlet,它支持 HEAD,最好还支持 HTTP Range 请求。

鉴于您明显抄袭了 OmniFaces Faces#sendFile() 的源代码,我建议抄袭另一个 OmniFaces 工件 FileServlet 的源代码。您可以在此处找到快照展示和源代码链接:OmniFaces (2.2) FileServlet

你可以这样使用它:

@WebServlet("/webinar_animation.mov")
public class YourFileServlet extends FileServlet {

    @Override
    protected File getFile(HttpServletRequest request) throws IllegalArgumentException {
        return new File("E:\\Animation\\IA\\Learning movies\\webinar1\\01_Aug_webinar_08\\Aug08_edited_webinar_animation.mov");
    }

}
<a href="#{request.contextPath}/webinar_animation.mov">Download file</a>

另见:

【讨论】:

  • 谢谢。是的,我搜索了很多,最后我意识到我必须使用 OmniFaces 中的这些代码,因为下载时我无法获得正确的文件扩展名。所以你的意思是,我必须使用这些类,而不是使用 java I/O 中的文件将 if 发送到我的 sendFile 函数?
  • 基本上,不使用不支持 HTTP Range 的 JSF 表单 (POST) 和支持 bean,而是使用 HTML 链接 (GET) 和支持 HTTP Range 的 servlet。
猜你喜欢
  • 2020-03-14
  • 2015-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多