代码之家  ›  专栏  ›  技术社区  ›  user10367961

在响应返回到客户端后清除

  •  2
  • user10367961  · 技术社区  · 7 年前

    语境:

    我有一个用于下载zip存档的端点。

    @GetMapping
    public DeferredResult<StreamingResponseBody> download(/**params**/) {
    
    }
    

    由于文件的数量和文件大小,无法将所有文件都保存在内存中(即,我必须从外部服务读取文件块,将其存储到临时目录,创建一个zip存档,将文件块写入zip,在存档完成后删除所有临时文件- 此时,我只剩下磁盘上的存档文件了。 -然后将zip流回到客户机)。

    我已经设法实现了这一功能,但我不确定在请求之后,哪种方法是最好的清理方法(请注意,该服务由多个客户机使用,因此应该可以同时进行多个下载)。

    目前,我正在使用 HandlerInterceptor 为中的存档生成随机名称 preHandle 方法并将其作为请求属性传递。请求属性将传递给生成存档的服务,并用作存档名称。然后,在 afterCompletion 方法,我从请求属性中读取存档名并删除存档。

    class ZipInterceptor implements HandlerInterceptor {
    
        public static final String ZIP_ATTRIBUTE_NAME = "zipName";
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if(isApplicable(request)){
                request.setAttribute(ZIP_ATTRIBUTE_NAME, generateZipName());
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            if(isApplicable(request)){
                deleteZip((String)request.getAttribute(ZIP_ATTRIBUTE_NAME));
            }
        }
    }
    

    我考虑过的另一种方法:

    • 将存档名返回给客户机(作为头文件或下载文件的名称),并依赖客户机调用新的端点来删除存档。主要的缺点是我没有办法强迫客户机使用这个协议(最终可能磁盘已满)。
    • 每小时(或另一个时间间隔)运行一个作业并清除旧的存档。缺点是,我不确定文件是否已完成流式处理返回到客户机(因此,对于足够大的文件,任何时间间隔都将删除尚未完成流式处理的文件)。

    在你看来,处理这种情况的最佳方法是什么?

    1 回复  |  直到 6 年前
        1
  •  1
  •   user10367961    7 年前

    正如JB Nizet在评论中指出的,最好的方法是 根本不将文件存储在磁盘上 .

    如果在将请求返回到客户机之后,您的特定上下文在磁盘上留下了文件,那么可以使用下一种方法来除去它们。

    class CleanupInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            // do cleanup here
        }
    }
    

    如果有人找到一个更优雅的解决方案来解决这个问题,请把你的答案贴在这里。