文件

§必要動作

§什麼是必要動作?

必要動作是 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。有問題或建議要分享嗎?請前往 我們的社群論壇 與社群展開對話。