§必要動作
§什麼是必要動作?
必要動作是 Action[A] 底層較為簡單的類型。若要了解必要動作,我們需要了解 Play 架構。
Play 的核心非常小,周圍環繞著大量有用的 API、服務和結構,以簡化 Web 程式設計任務。
基本上,Play 的動作 API 抽象具有下列類型
RequestHeader -> Array[Byte] -> Result
上述 運算 會採用要求標頭 RequestHeader
,然後採用要求主體為 Array[Byte]
,並產生 Result
。
現在此類型假設將請求主體完全放入記憶體(或磁碟)中,即使你只想從中計算一個值,或更好地將其轉發到 Amazon S3 等儲存服務。
我們寧願接收請求主體區塊作為串流,並在必要時能夠逐步處理它們。
我們需要變更的是第二個箭頭,使其接收其輸入作為區塊,並最終產生結果。有一個類型可以完全執行此操作,它稱為 Accumulator
,並需要兩個類型參數。
Accumulator[E,R]
是一種 箭頭 類型,它將接收其輸入作為類型 E
的區塊,並最終傳回 R
。對於我們的 API,我們需要一個 Accumulator,它接收 ByteString
的區塊(基本上是位元組陣列的更有效率的包裝器),並最終傳回 Result
。因此,我們稍微修改類型為
RequestHeader -> Accumulator[ByteString, Result]
對於第一個箭頭,我們僅使用 Function[From, To],它可以用 =>
作為類型別名
RequestHeader => Accumulator[ByteString, Result]
現在,如果我為 Accumulator[E,R]
定義一個中綴類型別名
type ==>[E,R] = Accumulator[E,R]
,那麼我可以更有趣的方式撰寫類型
RequestHeader => ByteString ==> Result
這應該讀作:取得請求標頭,取得表示請求主體的 ByteString
區塊,並最終傳回 Result
。這正是 EssentialAction
類型的定義方式
trait EssentialAction extends (RequestHeader => Accumulator[ByteString, Result])
另一方面,Result
類型可以抽象地視為回應標頭和回應主體
case class Result(header: ResponseHeader, body: ByteString)
但是,如果我們想要逐步將回應主體傳送給客戶端,而不用將其全部填入記憶體中,該怎麼辦?我們需要改進我們的類型。我們需要將主體類型從 ByteString
替換為產生 ByteString
塊的類型。
我們已經有一個類型,稱為 Source[E, _]
,這表示它能夠產生 E
塊,在我們的案例中為 Source[ByteString, _]
case class Result(header: ResponseHeader, body: Source[ByteString, _])
如果我們不必逐步傳送回應,我們仍然可以將整個主體作為單一塊傳送。在實際的 API 中,Play 使用 HttpEntity
包裝器類型支援不同類型的實體,它支援串流、分塊和嚴格實體。
請注意,Play 的內建輔助程式,例如 Ok(myObject)
,會使用隱含的 Writeable[E]
執行個體,將 myObject
轉換為實體,該執行個體會從實體 E
建立 HttpEntity
。
§重點
必要的 Play HTTP API 非常簡單
RequestHeader -> Accumulator[ByteString, Result]
或更有趣的
RequestHeader => ByteString ==> Result
其讀法如下:取得 RequestHeader
,然後取得 ByteString
塊,並傳回回應。回應包含 ResponseHeaders
和主體,而主體是可轉換為 ByteString
的值塊,以寫入表示在 Source[E, _]
類型中的 socket。
下一頁:HTTP 篩選器
在此文件說明中發現錯誤?此頁面的原始程式碼可以在 這裡 找到。在閱讀 文件說明指南 之後,請隨時提交 pull request。有問題或建議要分享嗎?請前往 我們的社群論壇 與社群展開對話。