堆空间中的缓冲响应会导致大文件出现问题

2023-12-30

我有一个网络服务器项目,在尝试下载大文件时遇到异常。该文件通过流读取并写入 ServletOutputStream。

示例代码:

private void readFromInput(BufferedInputStream fis,
    ServletOutputStream sout) throws IOException
    {
    byte[] buf = new byte[4096];
    int c = 0;
    while ((c = fis.read(buf)) != -1)
    {
        sout.write(buf, 0, c);    
    }
    fis.close();
}

当我查看回溯时,我看到一些过滤器被执行。

这是异常的一些部分:

javax.servlet.ServletException: #{DownloaderBean.actionDownload}: 
java.lang.OutOfMemoryError: Java heap space
javax.faces.webapp.FacesServlet.service(FacesServlet.java:256)
org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:144)
org.ajax4jsf.framework.ajax.xmlfilter.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:127)
org.ajax4jsf.framework.ajax.xmlfilter.BaseFilter.doFilter(BaseFilter.java:277)
....
....
....

java.lang.OutOfMemoryError: Java heap space
java.io.ByteArrayOutputStream.write(Unknown Source)
org.apache.myfaces.webapp.filter.ExtensionsResponseWrapper$MyServletOutputStream.write(ExtensionsResponseWrapper.java:135)

当我查看 ExtensionFilter 代码时:

http://grepcode.com/file/repo1.maven.org/maven2/org.apache.myfaces.tomahawk/tomahawk12/1.1.7/org/apache/myfaces/webapp/filter/ExtensionsFilter.java http://grepcode.com/file/repo1.maven.org/maven2/org.apache.myfaces.tomahawk/tomahawk12/1.1.7/org/apache/myfaces/webapp/filter/ExtensionsFilter.java

此页面上有一部分:

"When the ExtensionsFilter is enabled, and the DefaultAddResources implementation is 
used then there is no way to avoid having the response buffered in memory"

我猜想这些过滤器缓冲堆上的响应并导致问题。有没有办法阻止此过滤器应用于特定页面/链接?或者我应该采用另一种方式来处理这个问题?


我的面孔ExtensionsFilter显然正在缓冲entire服务器内存中的响应直到最后一位。因此,你基本上有两个选择:

  1. 摆脱 MyFacesExtensionsFilter.

  2. 不要让请求到达 MyFacesExtensionsFilter.

如果您确实需要它来满足 Web 应用程序中的某些功能要求,则选项 1 可能是极端的,但如果可以找到替代方案,则也是可行的。例如。如果您只需要它来处理文件上传,那么您可以考虑使用替代组件库,甚至是标准的 JSF 2.2 组件库。

选项 2 可通过两种方式实现:

  1. 更改过滤器的 URL 模式,以便下载请求不会命中它。如果您能弄清楚您到底需要哪些 URLExtensionsFilter,那么你可以改变它的<filter-mapping>因此,它只会在这些 URL 上生效,而不是在全局上生效FacesServlet.

    例如。何时应该调用它/upload.jsf仅,替换<servlet-name> by <url-pattern>:

    <filter-mapping>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <url-pattern>/upload.jsf</url-pattern>
    </filter-mapping>
    

    仅当您实际从同一页面执行下载操作时,这才会很麻烦。

  2. 更改下载请求 URL,使其不会命中过滤器。前提是你不能只需将这些文件放入公共 Web 内容中,也不能将包含这些文件的文件夹添加为另一个上下文 https://stackoverflow.com/questions/1812244/simplest-way-to-serve-static-data-from-outside-the-application-server-in-a-java/1812356#1812356(例如,因为这些文件是动态生成的),一种方法是将所有下载服务代码从 JSF 托管 bean 移动到普通的 servlet。然后让链接 URL 或表单操作指向该 servlet。由于该请求不会命中FacesServlet, the ExtensionsFilter也不会被击中。

    E.g.

    @WebServlet("/files/*")
    public class FileServlet extends HttpServlet {
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String filename = request.getPathInfo().substring(1);
    
            // Just do your job to get the File or InputStream, depending on the functional requirements.
            // This kickoff example just allocates a file in the file system.
            File file = new File("/path/to/files", filename);
            response.setHeader("Content-Type", getServletContext().getMimetype(filename));
            response.setHeader("Content-Length", String.valueOf(file.length()));
            response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
            Files.copy(file.toPath(), response.getOutputStream());
        }
    
    }
    

    (注意:如果您还没有使用 Servlet 3.0,只需替换@WebServlet通过通常的 servlet 映射web.xml;如果您仍然没有使用 Java 7,只需替换Files#copy()按平常的InputStream/OutputStream循环样板)

    像下面这样调用它(假设 JSP 上有旧版 JSF 1.2,考虑到您链接到 JSF 1.2 的 Tomahawk 源代码;因此不支持模板文本中的 EL)。

    <h:outputLink value="#{request.contextPath}/files/#{bean.filename}">
        <h:outputText value="Download #{bean.filename}" />
    </h:outputLink>
    

    如果下载需要额外的参数,只需使用<f:param>:

    <h:outputLink value="#{request.contextPath}/files/#{bean.filename}">
        <f:param name="foo" value="#{bean.foo}" />
        <f:param name="bar" value="#{bean.bar}" />
        <h:outputText value="Download #{bean.filename}" />
    </h:outputLink>
    

    然后可以在 servlet 中获取,如下所示:

    String foo = request.getParameter("foo");
    String bar = request.getParameter("bar");
    // ...
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

堆空间中的缓冲响应会导致大文件出现问题 的相关文章

随机推荐

  • 重置 Android 文本视图最大行数

    我想制作一个可以通过用户触摸折叠的 TextView 当 TextView 折叠时 我设置textView setMaxLines 4 如何在扩展方法中清除此状态 我只能想到打电话setMaxLines 值很大 例如10000 有更好的方法
  • 并行运行多个 future,超时返回默认值

    我必须并行运行多个 future 并且程序不应崩溃或挂起 现在 我一一等待 future 如果出现 TimeoutException 则使用后备值 val future1 start future1 val future2 start fu
  • 如果提交是由标签引用而不是由分支引用,那么它是否会被垃圾收集?

    我有一个引用提交的带注释的标签 如果带注释有关系吗 并且没有分支引用那里 一段时间后提交会被垃圾收集吗 不 提交不会被垃圾收集 来自标签的引用足以使提交保持活动状态
  • eslint 使用配置了 jsconfig.json 的路径映射解决导入错误

    这是我的项目结构 src assets components constants helpers pages routes eslintrc json jsconfig json App js index js 我厌倦了 import So
  • BlockingCollection 与 Parallel.For 挂起?

    我正在玩BlockingCollection尝试更好地理解它们 但我很难理解为什么当我使用Parallel For 我只是添加一个数字 生产者 var blockingCollection new BlockingCollection
  • Request.IsLocal 替代方案?

    据我所理解 请求 IsLocal http msdn microsoft com en us library system web httprequest islocal aspx在两种情况下返回 true 如果请求发起者的IP地址是127
  • SwiftUI 自定义 PickerStyle

    我正在尝试写一个自定义PickerStyle看起来类似于SegmentedPickerStyle 这是我目前的状态 import SwiftUI public struct FilterPickerStyle PickerStyle pub
  • 使用 SocketChannel Android 连接到 websocket

    我编写了连接到 websocket 服务器 服务器应用程序和 android 应用程序的 android 应用程序Autobahn网络套接字库 我可以成功连接服务器并与服务器交换消息 但一段时间后 20 30 分钟后 Android 应用程
  • 多态 has_and_belongs_to_many

    如何定义 has and belongs to many 多态关联 情况 想象一下我们有用户 曲目 列表等 并且所有这些模型都可以被标记并使用此标签进行过滤 我想做的是 Use has and belongs to many这使得标签可以拥
  • 使用 sql 选择的值作为另一个选择的行名称

    在 MSSQL 服务器上 给定表 TABLE values int id timestamp date int value TABLE value type int value id foreign key on values id tex
  • 通过 setName() 比较组件。

    我正在编写一个图像拼图游戏 代码的一部分是将用户选择的片段与正确图像的片段进行比较 每个图像片段都已作为 ImageIcon 添加到 JButton 需要一个标识符来区分每个图像片段并进行比较 我正在为每个创建为标识符的 JButton 设
  • Java - 字段名称的别名

    假设我有一个对象 Object A String field1 abc String field2 xyz 上面的 json 是 ObjectA field1 abc field2 xyz 我试图在发送 json 之前为字段名称创建一个新的
  • 构建一个简单的键盘记录器 Android 应用程序:虚拟键盘的辅助功能研究

    我一直在尝试寻找一些资源 以便为 Android 平台 APILevel 17 上的辅助功能研究项目构建键盘记录器 Android 应用程序 应用程序的界面将是一个简单的 编辑文本 用户使用以下命令键入的字段虚拟屏幕键盘 从输入设置中选择所
  • Dalvik 到 Java SE 通信

    我正在计划开发一个 Android 应用程序 它需要后端服务器来与该应用程序的其他用户同步数据 我计划用在 UNIX 服务器上运行的标准 java 编写这个服务器 我曾经直接在两个 Android 设备之间执行此操作 在这种情况下 我只是序
  • 如何对具有非数值的数据框进行分组和透视

    我正在使用 Python 并且有一个包含 6 列的数据集 R Rc J T Ca 和 Cb 我需要先 聚合 列 R 然后 聚合 以便对于每个 R 每一行都是唯一的 J Rc 是 R 的特征 Ca 和 Cb 是 T 的特征 查看下表会更有意义
  • 什么是 UI 状态?

    什么是 UI 状态 你能给我举一个类似的例子吗 例如 它是否指的是跟踪打开的选项卡之类的事情 我认为这个想法是应用有状态 并且 UI 反映了该状态 所以当你的应用程序启动时 它会像下面这样 1 初始状态 应用程序启动 2 加载初始数据 加载
  • 自动前缀过滤器在 Flask_Assets 中不起作用

    我尝试按照以下说明让 autoprefixer 过滤器与 Flask assets 一起使用Flask Assets 文档 https webassets readthedocs io en latest builtin filters h
  • 如何使用 core php 在 WordPress 中注册后自动登录

    几天来我一直在尝试让刚刚注册到我的 WordPress 网站的用户自动登录 然后将他们重定向到我选择的 URL 默认情况下 WordPress 会向您发送用户名和密码 然后您必须手动登录 这是一种彻底的痛苦 我怎样才能克服这个问题 我有自己
  • Java随机数

    初学者问题在这里 我尝试使用此代码创建一个随机数 int rand int Math random 10 但是 当打印到屏幕时 我一直收到 0 作为答案 只有在像这样加上括号之后 int rand int Math random 10 数字
  • 堆空间中的缓冲响应会导致大文件出现问题

    我有一个网络服务器项目 在尝试下载大文件时遇到异常 该文件通过流读取并写入 ServletOutputStream 示例代码 private void readFromInput BufferedInputStream fis Servle