3

我成功地使用 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 发行版。

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

4

2 回答 2

0

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

检测浏览器何时接收文件下载

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

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

于 2012-04-25T10:06:29.543 回答
0

您可以使用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 并进行自己的实现..

于 2013-02-09T09:30:26.370 回答