我成功使用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发行版。
有关如何获取有关何时将文件下载结束推送到用户浏览器的通知的任何想法?
答案 0 :(得分:0)
这似乎可以帮助你,因为它解决了一个类似的问题:
Detect when browser receives file download
我不确定您是否能够通过控制器中的renderBinary
和@After
注释完成此操作。某些浏览器端检测到下载,然后向服务器发送通知(ping下载结束)将起作用。
可能有另一种选择:使用WebSockets(通过套接字流式传输文件,然后让客户端回答),但这可能有点过头了:)
答案 1 :(得分: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并制作你自己的实现..