将响应返回给客户端后进行清理 [英] Clean up after response is returned to client

查看:149
本文介绍了将响应返回给客户端后进行清理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文:

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

I have an endpoint that is used to download a zip archive.

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

}

由于文件数和文件大小的原因,无法将它们全部保存在内存中(即,我必须从外部服务读取大块文件,将它们存储到临时目录中,创建一个zip归档文件,然后写入文件在压缩文件中,将所有临时文件删除.-这时,我只剩下磁盘上的存档文件-然后将压缩文件流回客户端).

Due to the number of files and file sizes, keeping all of them in memory is not possible (i.e. I have to read chunks of files from an external service, store them to a temporary directory, create a zip archive, write files in chunks to the zip, delete all temporary files after the archiving is done - at this point I am left only with the archive on disk - and afterwards stream the zip back to the client).

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

I've managed to implement the functionality, but I am not sure which is the best way to clean up after a request (note that the service is used by multiple clients - so multiple downloads should be able to happen simultaneously).

当前,我正在使用HandlerInterceptor,该HandlerInterceptorpreHandle方法中为存档生成一个随机名称,并将其作为请求属性传递. request属性将传递给生成档案的服务,并用作档案名称.然后,在拦截器的afterCompletion方法中,我从request属性中读取档案名称并删除档案.

Currently, I am using a HandlerInterceptor that generates a random name for the archive in the preHandle method and passes it along as a request attribute. The request attribute is passed along to the service that generates the archive and is used as archive name. Then, in the afterCompletion method of the interceptor, I read the archive name from the request attribute and delete the archive.

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));
        }
    }
}

我考虑过的另一种方法:

  • 将存档名称返回给客户端(作为标头或下载文件的名称),并依靠客户端调用新的端点来删除存档.主要缺点是我无法强制客户端使用此协议(并且可能最终会导致磁盘已满).
  • 每小时(或每隔一个时间间隔)运行一次作业,并清理旧的存档.缺点是我不确定是否将文件完成流传输回客户端(因此,对于足够大的文件,任何时间间隔将删除尚未完成流传输的文件).

您认为哪种方法是应对这种情况的最佳方法?

Which would be, in your opinion, the best way to handle this scenario?

推荐答案

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

As JB Nizet pointed out in the comments, the best approach would be to not store the files on disk at all.

如果在请求返回给客户端之后,如果您的特定上下文使您在磁盘上留下文件,则可以使用下一种方法来删除它们.

If your specific context left you with files on disk after the request is returned to the client, you could use the next approach to get rid of them.

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
    }
}

如果有人找到解决此问题的更优雅的解决方案,请在此处发布您的答案.

If anyone finds a more elegant solution to tackle this, please post your answer here.

这篇关于将响应返回给客户端后进行清理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆