spray.io的文檔太晦澀,啃起來太痛苦了。還有,屋裏真冷。路由
「路由」是spray-routing的中心概念,由於全部你用DSL建立的結構都是Route的子類型。在spray-routing中一個路由須要以下方式定義: html
type Route = RequestContext => Unit
它是一個把RequestContext做爲參數的函數的別名。 函數
不一樣於你最初所指望的,一個路由不返回任何東西。相反,全部響應處理(在路由處理完一個請求後須要完成的全部事情)是經過 RequestContext的響應器來執行的(in 「continuation-style」)。若是你不知道這意味着什麼的話,別擔憂。這些很快就會變得清晰。關鍵是,這種設計的優勢是徹底非阻塞以及 Actor友好的,由於這種方式,它能夠簡單地把一個RequestContext發送給另外一個Actor(以「fire-and-forget」的方 式),而沒必要擔憂結果處理。 this
一般當一個路由接收到一個請求(或者說是一個RequestContext)它能夠作這三件事中的一個: spa
第一種狀況至關清楚,經過調用complete將一個給定的響應發送到客戶端做爲這個請求的反應。第二種狀況中,「拒絕」意味着路由不想處理這個請 求。You’ll see further down in the section about route composition what this is good for。第三種狀況一般是一個錯誤。若是一個路由對請求不作任何事情,它會簡單的不對它產生做用。這意味着客戶端將接收不到響應,直到請求超時,此時會生 成一個「500 Internal Server Error 」響應。所以你的路由一般以完成或拒絕請求來結束。 scala
路由是普通的函數(RequestContext => Unit),最簡單的路由是: 設計
ctx => ctx.complete("Response")
更簡短的: code
_.complete("Response")
還有更短的(用complete指令): htm
complete("Response")
這些都是不一樣的方式定義相同的東西,即一個路由用一個靜態響應簡單地完成全部請求。 路由
雖然你能夠把全部應用邏輯寫到一個函數裏,來檢查RequestContext並根據它的屬性來完成它,但這種設計很難閱讀,維護和重用。所以spray-routing容許你經過組合簡單的路由來構造更復雜的路由。 文檔
用簡單路由構造複雜路由有三個基本的操做:
最後一點經過簡單的~操做來完成,它對全部路由都有效,例如一個隱式的「擴展」。前兩點由Directives來提供,spray-routing已經預約義了大多數,你也能夠本身簡單地建立。Directives給予spray-routing大部分能力和靈活性。
基本上,當你經過嵌套和~操做來結合指令和自定義路由時,你構造了一個樹形路由結構。當一個請求到來,它被注入到樹的根,並以深度優先的方式向下流經全部分支,直到有節點完成,或所有拒絕。
考慮這個例子:
val route = a { b { c { ... // route 1 } ~ d { ... // route 2 } ~ ... // route 3 } ~ e { ... // route 4 } }有5個構成路由樹的指令。
路由3所以能夠被視爲一種「全方位」路由(若是路由連接前面的位置拒絕)。這種機制可使複雜的過濾邏輯很容易實現:簡單地把最具體的狀況提早並把通常狀況放後面。