2012-04-24 60 views
2

我成功使用Play 1.2.4向使用renderBinary()方法的用户提供大型二进制文件下载。在Play框架中完成文件下载时的通知

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

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

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

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

关于如何获得文件下载结束时间通知给用户浏览器的任何想法?

回答

0

看来,这可能会帮助你,因为它铲球一个某种程度上类似的问题:

Detect when browser receives file download

我不知道你会EB能够通过renderBinary做到这一点,也不是@After注解控制器。一些浏览器端检测到的下载,然后通知服务器(ping下载的结束)将工作。

可能有一种替代方案:使用的WebSockets(通过插座流的文件,然后为德客户回答),但它可能是矫枉过正这:)

+0

通过websockets上传文件的关键修复即将推出... https://github.com/playframework/play1/pull/709 – 2013-12-16 14:28:18

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并自行实施。

+0

除了ArchivedEventStream将DROP数据包在缓冲区最大化....一个轮询请求修复只有websockets的EventStream是在这里......有人需要说出来,如果他们想要ArchivedEventStream不像今天一样丢弃数据包... https ://github.com/playframework/play1/pull/709 – 2013-12-16 14:29:27