从支持 bean 提供下载时,下载加速器会导致 org.apache.catalina.connector.ClientAbortException: java.io.IOException
Download accelerator causes org.apache.catalina.connector.ClientAbortException: java.io.IOException when providing download from backing bean
我使用 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,但是当我使用这些下载管理器软件(启用它们AddOns)我收到这些错误
会发生什么?我知道这个错误发生在一些连接丢失的情况下......但我没有关闭我的页面或任何导致这个错误的东西!
这是我的 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 和 HEAD 请求(即只需在浏览器的地址栏中键入 URL 时)幂等可用的文件,并且最好还支持 HTTP Range
请求(因此可以打开多个 HTTP 连接以同时下载部分内容)。 JSF 支持 bean 方法仅在 POST 请求时被调用(即当提交带有 method="post"
的 HTML 表单时)。 ClientAbortException
发生是因为下载加速器在嗅探 HEAD 和 Range
支持时没有得到预期的响应并中止了它。
如果这些文件是静态的,因此不是动态的,那么最好的办法是创建一个单独的 servlet,它支持 HEAD 请求,最好也支持 HTTP Range
请求。
鉴于您显然从 OmniFaces Faces#sendFile()
, I'd suggest to rip off the source code of another OmniFaces artifact, the FileServlet
. You can find snapshot showcase and source code link here: 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>
另请参阅:
- How to stream audio/video files such as MP3, MP4, AVI, etc using a Servlet
我使用 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,但是当我使用这些下载管理器软件(启用它们AddOns)我收到这些错误
会发生什么?我知道这个错误发生在一些连接丢失的情况下......但我没有关闭我的页面或任何导致这个错误的东西! 这是我的 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 和 HEAD 请求(即只需在浏览器的地址栏中键入 URL 时)幂等可用的文件,并且最好还支持 HTTP Range
请求(因此可以打开多个 HTTP 连接以同时下载部分内容)。 JSF 支持 bean 方法仅在 POST 请求时被调用(即当提交带有 method="post"
的 HTML 表单时)。 ClientAbortException
发生是因为下载加速器在嗅探 HEAD 和 Range
支持时没有得到预期的响应并中止了它。
如果这些文件是静态的,因此不是动态的,那么最好的办法是创建一个单独的 servlet,它支持 HEAD 请求,最好也支持 HTTP Range
请求。
鉴于您显然从 OmniFaces Faces#sendFile()
, I'd suggest to rip off the source code of another OmniFaces artifact, the FileServlet
. You can find snapshot showcase and source code link here: 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>
另请参阅:
- How to stream audio/video files such as MP3, MP4, AVI, etc using a Servlet