型別安全路由
必要相依性:io.ktor:ktor-server-resources
程式碼範例: resource-routing
Ktor 提供了 Resources 外掛程式,可讓您實作型別安全 路由。要實現此功能,您需要建立一個作為型別化路由的類別,然後使用 @Resource 關鍵字為該類別加上註解。請注意,@Resource 註解具有由 kotlinx.serialization 函式庫提供的 @Serializable 行為。
Ktor 用戶端提供了向伺服器發送 型別化請求 的能力。
新增相依性
新增 kotlinx.serialization
鑑於 資源類別 應具有 @Serializable 行為,您需要按照 Setup 章節所述新增 Kotlin serialization 外掛程式。
新增 Resources 相依性
要使用 Resources,您需要在建置指令碼中包含 ktor-server-resources 構件:
安裝 Resources
要將 Resources 外掛程式安裝至應用程式,請將其傳遞給指定
install 函式。 下方的程式碼片段顯示如何安裝 Resources ... - ... 在
embeddedServer函式呼叫中。 - ... 在明確定義的
module中,該模組是Application類別的擴充函式。
建立資源類別
每個資源類別都應具有 @Resource 註解。 下面,我們將查看幾個資源類別的範例 —— 定義單一路徑片段、查詢和路徑參數等。
資源 URL
下方的範例顯示如何定義 Articles 類別,該類別指定一個在 /articles 路徑上回應的資源。
import io.ktor.resources.*
@Resource("/articles")
class Articles()具有查詢參數的資源
下方的 Articles 類別具有 sort 字串屬性,其作為 查詢參數 並允許您定義一個在具有 sort 查詢參數的以下路徑上回應的資源:/articles?sort=new。
@Resource("/articles")
class Articles(val sort: String? = "new")具有巢狀類別的資源
您可以巢狀類別以建立包含多個路徑片段的資源。請注意,在這種情況下,巢狀類別應具有一個外部類別型別的屬性。 下方的範例顯示一個在 /articles/new 路徑上回應的資源。
@Resource("/articles")
class Articles() {
@Resource("new")
class New(val parent: Articles = Articles())
}具有路徑參數的資源
下方的範例示範如何新增 巢狀 的 {id} 整數 路徑參數,該參數會配對路徑片段並將其擷取為名為 id 的參數。
@Resource("/articles")
class Articles() {
@Resource("{id}")
class Id(val parent: Articles = Articles(), val id: Long)
}舉例來說,此資源可用於在 /articles/12 上進行回應。
範例:用於 CRUD 操作的資源
讓我們總結上述範例,並為 CRUD 操作建立 Articles 資源。
@Resource("/articles")
class Articles(val sort: String? = "new") {
@Resource("new")
class New(val parent: Articles = Articles())
@Resource("{id}")
class Id(val parent: Articles = Articles(), val id: Long) {
@Resource("edit")
class Edit(val parent: Id)
}
}此資源可用於列出所有文章、發布新文章、編輯文章等。我們將在下一章中了解如何為此資源 定義路由處理常式 。
您可以在此處找到完整範例:resource-routing。
定義路由處理常式
要為型別化資源 定義路由處理常式,您需要將資源類別傳遞給動詞函式(get、post、put 等)。 例如,下方的路由處理常式在 /articles 路徑上回應。
@Resource("/articles")
class Articles()
fun Application.module() {
install(Resources)
routing {
get<Articles> { articles ->
// 取得所有文章 ...
call.respondText("文章列表:$articles")
}
}
}下方的範例顯示如何為在 範例:用於 CRUD 操作的資源 中建立的 Articles 資源定義路由處理常式。請注意,在路由處理常式內部,您可以將 Article 作為參數存取並取得其屬性值。
fun Application.module() {
install(Resources)
routing {
get<Articles> { article ->
// 取得所有文章 ...
call.respondText("文章列表,排序方式:${article.sort}")
}
get<Articles.New> {
// 顯示具有用於建立新文章之欄位的頁面 ...
call.respondText("建立新文章")
}
post<Articles> {
// 儲存文章 ...
call.respondText("文章已儲存", status = HttpStatusCode.Created)
}
get<Articles.Id> { article ->
// 顯示 ID 為 ${article.id} 的文章 ...
call.respondText("ID 為 ${article.id} 的文章", status = HttpStatusCode.OK)
}
get<Articles.Id.Edit> { article ->
// 顯示具有用於編輯文章之欄位的頁面 ...
call.respondText("編輯 ID 為 ${article.parent.id} 的文章", status = HttpStatusCode.OK)
}
put<Articles.Id> { article ->
// 更新文章 ...
call.respondText("ID 為 ${article.id} 的文章已更新", status = HttpStatusCode.OK)
}
delete<Articles.Id> { article ->
// 刪除文章 ...
call.respondText("ID 為 ${article.id} 的文章已刪除", status = HttpStatusCode.OK)
}
}
}以下是處理每個端點請求的一些提示:
get<Articles>此路由處理常式應該根據
sort查詢參數回傳所有文章。 例如,這可能是包含所有文章的 HTML 頁面 或 JSON 物件。get<Articles.New>此端點會回應包含用於建立新文章之欄位的 Web 表單。
post<Articles>post<Articles>端點應該接收使用 Web 表單傳送的 參數。 Ktor 還允許您使用ContentNegotiation外掛程式將 JSON 資料接收為 物件。get<Articles.Id>get<Articles.Id.Edit>此端點會回應包含用於編輯現有文章之欄位的 Web 表單。
put<Articles.Id>與
post<Articles>端點類似,put處理常式接收使用 Web 表單傳送的 表單參數。delete<Articles.Id>此路由處理常式會刪除具有指定識別碼的文章。
您可以在此處找到完整範例:resource-routing。
從資源建立連結
除了將資源定義用於路由之外,它們還可以用於建立連結。 這有時被稱為 反向路由(reverse routing)。 如果您需要將這些連結新增至使用 HTML DSL 建立的 HTML 文件,或者需要產生 重新導向回應,則從資源建立連結可能會很有幫助。
Resources 外掛程式使用多載的 href 方法擴充了 Application,該方法可讓您從 Resource 產生連結。例如,下方的程式碼片段會為 上述定義 的 Edit 資源建立連結:
val link: String = href(Articles.Id.Edit(Articles.Id(id = 123)))由於祖父級 Articles 資源定義了具有預設值 new 的 sort 查詢參數,因此 link 變數包含:
/articles/123/edit?sort=new要產生指定主機和協定的 URL,您可以為 href 方法提供 URLBuilder。 還可以使用 URLBuilder 指定額外的查詢參數,如本範例所示:
val urlBuilder = URLBuilder(URLProtocol.HTTPS, "ktor.io", parameters = parametersOf("token", "123"))
href(Articles(sort = null), urlBuilder)
val link: String = urlBuilder.buildString()隨後 link 變數包含:
https://ktor.io/articles?token=123範例
下方的範例顯示如何將從資源建立的連結新增至 HTML 回應中:
get {
call.respondHtml {
body {
this@module.apply {
p {
val link: String = href(Articles())
a(link) { +"取得所有文章" }
}
p {
val link: String = href(Articles.New())
a(link) { +"建立新文章" }
}
p {
val link: String = href(Articles.Id.Edit(Articles.Id(id = 123)))
a(link) { +"編輯現有文章" }
}
p {
val urlBuilder = URLBuilder(URLProtocol.HTTPS, "ktor.io", parameters = parametersOf("token", "123"))
href(Articles(sort = null), urlBuilder)
val link: String = urlBuilder.buildString()
i { a(link) { +link } }
}
}
}
}
}您可以在此處找到完整範例:resource-routing。
