2012-07-13 39 views
5

我想了解Play 2.0框架的反應式I/O概念。爲了從一開始就得到更好的理解,我決定跳過框架的幫助程序來構造不同種類的迭代,並從頭開始編寫自定義Iteratee,供BodyParser用於解析請求主體。爲什麼調用錯誤或在BodyParser的迭代器中完成請求在Play Framework 2.0中掛起?

IterateesScalaBodyParser文件和有關遊戲的反應我兩個報告提供的信息開始/ O這是我想出了:

import play.api.mvc._ 
import play.api.mvc.Results._ 
import play.api.libs.iteratee.{Iteratee, Input} 
import play.api.libs.concurrent.Promise 
import play.api.libs.iteratee.Input.{El, EOF, Empty} 

01 object Upload extends Controller { 
02 def send = Action(BodyParser(rh => new SomeIteratee)) { request => 
03  Ok("Done") 
04 } 
05 } 
06 
07 case class SomeIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, received: Int = 0) extends Iteratee[Array[Byte], Either[Result, Int]] { 
08 println(state + " " + input + " " + received) 
09 
10 def fold[B](
11  done: (Either[Result, Int], Input[Array[Byte]]) => Promise[B], 
12  cont: (Input[Array[Byte]] => Iteratee[Array[Byte], Either[Result, Int]]) => Promise[B], 
13  error: (String, Input[Array[Byte]]) => Promise[B] 
14 ): Promise[B] = state match { 
15  case 'Done => { println("Done"); done(Right(received), Input.Empty) } 
16  case 'Cont => cont(in => in match { 
17  case in: El[Array[Byte]] => copy(input = in, received = received + in.e.length) 
18  case Empty => copy(input = in) 
19  case EOF => copy(state = 'Done, input = in) 
20  case _ => copy(state = 'Error, input = in) 
21  }) 
22  case _ => { println("Error"); error("Some error.", input) } 
23 } 
24 } 

(注:所有這些東西都是新的我,所以請原諒,如果這是完全廢話。) Iteratee是非常愚蠢的,它只是讀取所有塊,總結收到的字節數,並打印出一些消息。當我用一些數據調用控制器動作時,一切都按預期工作 - 我可以觀察到Iteratee接收到所有塊,並且當讀取所有數據時,它切換到完成狀態並且請求結束。

現在我開始玩的代碼,因爲我想看到這兩種情況下的行爲:

  • 切換到狀態錯誤讀取所有輸入之前。
  • 在讀取所有輸入之前切換到狀態,並返回Result而不是Int

我對上述文件的理解是,兩者都應該是可能的,但實際上我無法理解觀察到的行爲。爲了測試我改變線17上面的代碼的第一種情況:

17  case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Error else 'Cont, input = in, received = received + in.e.length) 

所以我剛添加如果收到超過10000個字節切換到錯誤狀態的條件。我得到的輸出是這樣的:

'Cont Empty 0 
'Cont El([[email protected]) 8192 
'Error El([[email protected]) 16384 
Error 
Error 
Error 
Error 
Error 
Error 
Error 
Error 
Error 
Error 
Error 

然後請求永遠掛起並永不結束。我從上面提到的文檔中獲得的期望是,當我調用Iteratee的fold中的error函數時,應該停止處理。這裏發生的事情是,在調用error之後,迭代器的摺疊方法被調用了好幾次 - 那麼請求就會掛起。

當我在讀取所有輸入之前切換到完成狀態時,行爲非常相似。改變15行至:

15 case 'Done => { println("Done with " + input); done(if (input == EOF) Right(received) else Left(BadRequest), Input.Empty) } 

和管線17到:

17  case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Done else 'Cont, input = in, received = received + in.e.length) 

產生以下輸出:

'Cont Empty 0 
'Cont El([[email protected]) 8192 
'Done El([[email protected]) 16384 
Done with El([[email protected]) 
Done with El([[email protected]) 
Done with El([[email protected]) 
Done with El([[email protected]) 

,並再次請求永遠掛起。

我的主要問題是爲什麼請求掛在上面提到的情況。如果有人能說明這一點,我將不勝感激!

回答

0

事情一定會隨Play 2.1發生變化 - Promise不再是參數化的,這個例子不再編譯。

相關問題