`

Play framework 2.0 -异步http编程

阅读更多

 

#处理异步结果

 

1.为什么使用异步Results?

 

直到现在,我们只能计算直接发送到客户端的result。这种方式并非总是奏效,result或许要花费高昂的计算代价,或者很长的web服务调用。

因为Play2.0工作时,action代码必须尽可能得快(例如非阻塞IO)。那么如果我们还没有计算完毕我们要返回什么结果呢?答案是响应一个

结果的承诺(对承诺有结果)。

 

2.如何创建一个Promise<Result>。

 

要创建一个承诺结果,我们首先需要一个给我吗计算出结果的真实数据的承诺:

 

Promise<Double> promiseOfPIValue = computePIAsynchronously();
	Promise<Result> promiseOfResult = promiseOfPIValue.map(
	  new Function<Double,Result>() {
	    public Result apply(Double pi) {
	      return ok("PI value computed: " + pi);
	    } 
	  }
	);
 

Play2.0的异步API方法会给你一个承诺(promise)。例如在你通过Play.libs.WS的API调用外部Web服务时,

或者你使用akka计划异步任务,或者使用akka和Actors沟通时。

 

一种简单的方法是使用akka的一段异步程序来获得一个Promise,这一过程在新的线程中执行,如:

 

Promise<Integer> promiseOfInt = Akka.future(
	  new Callable<Integer>() {
	    public Integer call() {
	      intensiveComputation();
	    }
	  }
	);
 

 

3.异步结果

 

现在我们要用到Results.Status了,在发送异步结果前,需要使用Results.AsyncResult包装一下实际的结果。,如:

 

public static Result index() {
	  Promise<Integer> promiseOfInt = Akka.future(
	    new Callable<Integer>() {
	      public Integer call() {
		intensiveComputation();
	      }
	    }
	  );
	  async(
	    promiseOfInt.map(
	      new Function<Integer,Result>() {
		public Result apply(Integer i) {
		  return ok("Got result: " + i);
		} 
	      }
	    )
	  );
	}
 

 

注意async()是用来从Promise<Result>建立一个AsyncResult的帮助方法。

 

#流Http响应

 

1.标准响应和Content-Length头

 

自Http 1.1,保持一个单一的连接为若干个Http请求和响应服务,服务器在做出响应时

必须发送正确的Content-Length Http头。

默认的,你可以发送一个简单的result,例如:

 

public static Result index() {
	  return ok("Hello World")
	}
 

 

在这个例子中你没有设置Content-Length头,当然,这是因为你发送的数据大家都认识,

Play能够为你计算出内容长度(注意基于文本的内容长度与你的编码格式有关),

并为你生成一个正确的头。

为了能计算出内容的长度(大小),你需要将全部的相应数据加载到内存中。

 

2.文件服务

 

如果把简单的内容数据全部装载进内存不是个问题,那么如果要装载一个巨大的数据呢?

比如说,我们要把一个很大的文件返回给web客户端。Play为这种常见的任务体统了易用的帮助方法:

public static Result index() {
          return ok(new java.io.File("/tmp/fileToServe.pdf"));
}
 

 

另外,这个方法也会自动为你计算文件名的Content-Type头。并且还会添加一个说明web客户端如果操作

这个响应的Content-Disposition头。默认使用Content-Disposition: attachment; filename=fileToServe.pdf

询问web浏览器下载该文件。

 

3.分块响应

 

现在,能够横好的和文件流内容一起工作了,因为我们讷讷感在将文件流化前算出它的长度来。

但是如何动态计算一个得不到内容大小的文件呢?

 

这种类型的响应我们得使用分块传输编码。

分块传输编码在Http 1.1中十一中数据传输机制,Web服务器提供若干块数据。它使用Transfer-Encoding Http响应头

而不是Content-Length头,不过Content-Length也是需要的,但是协议不用它。

因为服务器在开始将响应传输到客户端之前并不需要知道内容总共有多大。

 

每个块能够正确发送自身的大小,客户端可以正确接收这个块。数据传输最终以一个大小为0的块结束(就是说,

所有块发送完毕后,还要发送一个大小为0的块)。

 

这种方式的优势在于,我们可以提供实时数据。就是说一旦得到一个数据块,我们可以立即发送出去。缺点是,因为客户端

不知道整个内容的大小,因而不能显示一个正确的下载进度条。

 

比如说,我们有一个计算一些数据的动态输入流的服务。我们可以直接使用Play的分块响应来流化其内容:

public static Result index() {
	  InputStream is = getDynamicStreamSomewhere();
	  return ok(is);
	}
 

你也可以设置你自己的分块响应器。Play的JavaAPI支持文本和二进制的分块流(通过String和byte[])。

public static index() {
	  // Prepare a chunked text stream
	  Chunks<String> chunks = new StringChunks() {
	    
	    // Called when the stream is ready
	    public void onReady(Chunks.Out<String> out) {
	      registerOutChannelSomewhere(out);
	    }
	    
	  }
	  
	  // Serves this stream with 200 OK
	  ok(chunks);
	}

 

当流可以安全的写是onReady方法被调用。它为你提供了Chunks。Out,你可以向里面写。

 

 

#Comet 套接字(Comet sockets)

 

注意:详细的Comet技术请参阅Bayeux Protocol。http://svn.cometd.org/trunk/bayeux/bayeux.html

 

1.使用分块响应创建Comet套接字

 

分块响应(chunked responses)的一个很有用的用途是创建Comet 套接字,Comet套接字只是一个仅包含<script>元素的text/html分块响应。

每个分块里,我们写一个包含JavaScript的<script>标签,立即由web浏览器执行。通过这种方式,我们可以把事件

由服务器端发送到客户端:对每个消息而言,把它包装进JavaScript回调函数里,发给分块响应即可。

 

我们来写一个对这一概念的证明:创建一个产生调用<script>标签调用浏览器console.log功能的举例:

 

public static Result index() {
	  // Prepare a chunked text stream
	  Chunks<String> chunks = new StringChunks() {
	    
	    // Called when the stream is ready
	    public void onReady(Chunks.Out<String> out) {
	      out.write("<script>console.log('kiki')</script>");
	      out.write("<script>console.log('foo')</script>");
	      out.write("<script>console.log('bar')</script>");
	      out.close();
	    }
	    
	  }
	  
	  response().setContentType("text/html");
	  
	  ok(chunks);
	}
 

 

在浏览器上访问这个Action,你会看到有三个时间在浏览器控制台被记录。

 

2.使用play.libs.Comet帮助方法。

 

我们提供了一个Comet的帮助来操作这些comet分块流。它可以支持String和Json。

前面的代码可以改写成这样:

public static Result index() {
	  Comet comet = new Comet("console.log") {
	    public void onConnected() {
	      sendMessage("kiki");
	      sendMessage("foo");
	      sendMessage("bar");
	      close();
	    }
	  };
	  
	  ok(comet);
	}
 

3.永远的iframe技术

 

标准的技术是写一个Comet套接字,在一个iframe中加载无限循环的Comet响应,并且指定一个回调函数调用其父Fram。

public static Result index() {
	  Comet comet = new Comet("parent.cometMessage") {
	    public void onConnected() {
	      sendMessage("kiki");
	      sendMessage("foo");
	      sendMessage("bar");
	      close();
	    }
	  };
	  
	  ok(comet);
	}
 

Html页面类似于这样:

 

<script type="text/javascript">
  var cometMessage = function(event) {
    console.log('Received event: ' + event)
  }
</script>

<iframe src="/comet"></iframe>
 

 

#WebSocket

 

1.用WebSocket代替Comet

 

Comet Socket是一种向web浏览器发送活动事件的黑客手段。Comet仅支持从服务器到客户端的单向通信。要把事件推到服务器端,web浏览器要使用Ajax请求。

现代Web浏览器原生支持WebSockets的通过双向实时通信。

 

WebSocket是一个网络技术,通过一个单一传输控制协议(TCP)套接字,提供双向,全双工的通信通道。 WebSocket的API是由W3C制定,WebSocket协议已经被IETF规范为RFC6455。

WebSocket被设计为在Web浏览器和Web服务器上实现,但它可以通过任何客户端或服务器应用程序使用。因为一般的非80端口的tcp连接经常被除家庭环境外的管理员封锁,

当复用一个端口实现多个Websocket服务时,可以通过增加额外的协议开销,从而避开这些限制。这使得web应用提供实时的双向通信成为可能。

在Websocket出现之前,要实现全双工的双向通信只能使用Comet通道。

Comet的传输并不可靠,同时,由于TCP握手和HTTP头的存在,在传输小消息时它会低效。Websocket旨在不影响网络安全的前提下解决这些问题。

 

2.处理Websocket

 

到现在为止,我们使用一个简单的操作方法来处理标准的HTTP请求和发送标准的HTTP结果。WebSockets是一个完全不同的猛兽,无法通过标准的行动处理。

 

为了处理WebSocket你的方法必须返回WebSocket的,而不是一个Result:
	public static WebSocket<String> index() {
	  return new WebSocket<String>() {
	      
	    // Called when the Websocket Handshake is done.
	    public void onReady(WebSocket.In<String> in, WebSocket.Out<String> out) {
	      
	      // For each event received on the socket,
	      in.onMessage(new Callback<String>() {
		 public void invoke(String event) {
		     
		   // Log events to the console
		   println(event);  
		     
		 } 
	      });
	      
	      // When the socket is closed.
	      in.onClose(new Callback0() {
		 public void invoke() {
		     
		   println("Disconnected")
		     
		 }
	      });
	      
	      // Send a single 'Hello!' message
	      out.write("Hello!");
	      
	    }
	    
	  }
	}
 

 

一个WebSocket可以访问请求头(从HTTP请求发起的WebSocket连接),使您可以检索标准头文件和会话数据。但它不会访问任何请求体,也不访问HTTP响应。

当WebSocket准备好了,你得到输入和输入的通道。

在这个例子中,我们打印每个消息到控制台,我们发送一个Hello!消息:

public static WebSocket<String> index() {
	  return new WebSocket<String>() {
	      
	    public void onReady(WebSocket.In<String> in, WebSocket.Out<String> out) {
	      out.write("Hello!");
	      out.close()
	    }
	    
	  }
	}
 

 

 

 

 

0
0
分享到:
评论

相关推荐

    Play framework 2.0入门教程(四)的源代码,Play留言板(数据库版)

    此外,Play框架与Akka框架紧密集成,提供非阻塞I/O和异步处理能力,提升了应用的性能和响应速度。 在创建“Play留言板”应用时,我们首先要配置数据库连接。这里使用的是MySQL,一个广泛使用的开源关系型数据库管理...

    play2.0 for java developers.pdf

    ### Play2.0 for Java Developers #### 概述 Play2.0是一个现代的Web应用框架,它基于Java和Scala语言构建,旨在提供简洁、快速且可扩展的应用开发体验。对于Java开发者而言,Play2.0提供了一套完整的Java API,...

    play框架手册

    10.在HTTP下进行异步编程 - 89 - 暂停http请求 - 89 - Continuations - 90 - 回调Callbacks - 91 - HTTP response流 streaming - 92 - 使用WebSockets - 92 - 11.在play框架里使用Ajax - 94 - 通过jsAction标签使用...

    java开源框架下载集合

    **下载链接**: [http://download.playframework.org/releases/play-2.0.zip](http://download.playframework.org/releases/play-2.0.zip) Play Framework 是一款基于Java和Scala的高性能、轻量级Web应用开发框架。...

    play-scala-service-example:带有Macwire端点Akka类型的播放服务

    2. **Play Framework**: Play是基于Java和Scala的开源Web应用框架,遵循MVC(Model-View-Controller)架构模式,支持异步I/O和热加载,适合开发RESTful API。Play与Scala的集成使得开发者可以利用Scala的强大功能来...

    2015-Framework:2015年框架

    2015年的Play Framework 2.x版本支持异步I/O,适用于构建高性能的Web应用。 5. **Java EE 7**: Java企业版(Java EE)在2015年已经到了7版本,引入了WebSocket、Batch API、JAX-RS 2.0(RESTful服务)等新特性,...

    register-trust-settlor-frontend

    Play Framework是一个开源的Web框架,它支持异步操作,可以构建响应式的、高性能的Web应用。Scala的强类型系统和表达能力使得编写安全、可测试的代码变得更加容易。 **关于前端开发:** 前端开发主要关注用户在...

    Silverlight(2) - 1.0实例之支持录音和回放的钢琴(Silverlight+ASP.NET AJAX+DLINQ)

    至于Silverlight 2.0和1.0的区别,2.0版本引入了更多功能,如更丰富的UI控件、数据绑定、模板化以及对.NET Framework的更全面支持。这意味着如果使用Silverlight 2.0,我们可以通过数据绑定简化UI与模型之间的交互,...

    java_barcode_trial.zip_project

    4. **Web应用框架**:为了构建用户界面和处理HTTP请求,项目可能使用了Spring MVC、Struts2或Play Framework等Java Web框架。这些框架简化了开发过程,提供了模型-视图-控制器(MVC)架构,有利于代码组织和测试。 ...

    cds-reimbursement-claim-frontend

    在前端领域,Scala可以通过例如Play Framework这样的框架来构建Web应用程序,它支持异步I/O和HTTP服务,适合构建现代、响应式的Web应用。 尽管这个项目是前端相关的,但使用Scala可能意味着它依赖于后端服务进行...

    vat-deferral-new-payment-scheme-frontend

    这个项目是基于【Scala】编程语言进行开发的,Scala是一种强大的静态类型语言,它结合了面向对象和函数式编程的概念,提供高效、可扩展和维护性强的代码。 在增值税延期新支付方案前端中,我们可以预期以下几个关键...

    框架笔试-tang.docx

    * Play Framework 分析这些 Web 框架的优缺点包括: * Spring MVC:优点是轻量级、灵活、可扩展性强;缺点是学习曲线陡峭 * Struts 2.0:优点是功能强大、可扩展性强;缺点是配置复杂、学习曲线陡峭 * Hibernate:...

    mobile-notification-api:行动通知API

    3. **Java后端开发**:在Java后端,开发者可能使用Spring Boot或Play Framework等框架来构建API服务,这些框架提供了处理HTTP请求、路由、数据访问和事务管理等功能,使得开发高效且易于维护。 4. **RESTful API...

    mengtaiqi:檬太奇app及网站的后端

    1. **服务器架构**:可能采用了Spring Boot或Play Framework等Java Web框架,它们能快速搭建后端服务,并提供了丰富的功能支持。 2. **数据库管理**:可能使用了MySQL、PostgreSQL或者MongoDB等数据库系统,用于...

Global site tag (gtag.js) - Google Analytics