【问题标题】:Notification when file download completes in Play frameworkPlay 框架中文件下载完成时的通知
【发布时间】:2012-04-24 14:56:29
【问题描述】:

我已成功使用 Play 1.2.4 为使用 renderBinary() 方法的用户提供大型二进制文件下载。

我想知道用户何时真正完成下载。一般来说,我知道这在某种程度上是可能的,因为我以前做过。在我网站的旧版本中,我编写了一个简单的 servlet,用于提供二进制文件下载。一旦该 servlet 完成了文件内容的写出,就会发送一个通知。当然不是完美的,但仍然有用。在我的测试中,它确实提供了用户下载文件所需时间的指示。

查看 Play 源代码,我发现 play.mvc.results.RenderBinary 类有一个方便的 apply() 方法,我可以使用它。我编写了自己的 RenderBinary 版本,因此可以在 apply() 方法写完文件内容后发送通知。

我发现的问题是对 response.out.write() 的调用显然会缓存传出字节(通过 Netty?),所以即使我正在写出几兆字节的数据,对 play.mvc.Http 的调用也是如此。 Response.out.write() 在几秒钟内完成,即使下载器需要几分钟才能下载文件。

我不介意编写自定义类,尽管我更喜欢使用现有的 Play 1.2.4 发行版。

关于如何在文件下载结束时向用户的浏览器推送通知的任何想法?

【问题讨论】:

    标签: java playframework playframework-1.x


    【解决方案1】:

    这似乎可以帮助你,因为它解决了一个类似的问题:

    Detect when browser receives file download

    我不确定您是否能够通过 renderBinary 或控制器中的 @After 注释来做到这一点。一些浏览器端检测下载,然后通知服务器(ping 下载结束)会起作用。

    可能有另一种选择:使用 WebSockets(通过套接字流式传输文件,然后让客户端回答),但这可能是矫枉过正:)

    【讨论】:

    【解决方案2】:

    你可以使用ArchivedEventStream

    首先创建一个可序列化的 ArcivedEventStream 类..

    public class Stream<String> extends ArchivedEventStream<String> implements Serializable{
    
       public Stream(int arg0) {
            super(arg0);
       }
    
    }
    

    然后在你的控制器上...

    public static void downloadPage(){
        Stream<String> userStream = Cache.get(session.getId(),Stream.class);
        if( userStream == null){
            userStream = new Stream<String>(5);
            Cache.add(session.getId(), userStream);
        }
        render();
    }
    
    public static void download(){
        await(10000);// to provide some latency. actually no needed
        renderBinary(Play.getFile("yourfile!"));
    }
    
    public static void isDownloadFinished(){
        Stream<String> userStream = Cache.get(session.getId(),Stream.class);
        List<IndexedEvent<String>> list = await(userStream.nextEvents(0));
        renderJSON(list.get(0).data);
    
    }
    
    @After(only="download")
    static void after(){
        Stream<String> userStream = Cache.get(session.getId(),Stream.class);
        userStream.publish("ok");
    }
    

    在您的 html 上...

    #{extends 'main.html' /}
    
    #{set title:'downloadPage' /}
    <a href="download" target="_blank">download</a>
    
    <script>
    $(document).ready(function(){
    $.ajax('/application/isDownloadFinished',{success:function(data){
        if(data){
            console.log("downloadFinished");    
        }
    
    }});
    });
    
    </script>
    

    下载完成后,原始页面将检索通知。

    此代码只是一个示例。您可以阅读 ArchivedEventStream 的 api 并进行自己的实现..

    【讨论】:

    • 除了 ArchivedEventStream 将在缓冲区最大化时丢弃数据包......这里有一个轮询请求来修复仅适用于 websockets 的 EventStream......如果他们想要 ArchivedEventStream 的话,有人需要说出来不要像今天那样丢弃数据包...github.com/playframework/play1/pull/709
    猜你喜欢
    • 1970-01-01
    • 2018-02-20
    • 2021-05-02
    • 1970-01-01
    • 1970-01-01
    • 2012-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多