HTTP routing[翻譯]

原文:https://www.playframework.com/documentation/2.5.x/ScalaRouting

內(nèi)置HTTP路由器

路由器的職責(zé)是負(fù)責(zé)轉(zhuǎn)換每一個進(jìn)入的HTTP請求給Action

一個HTTP請求可以被看做是由MVC框架的事件。這個事件包含兩個主要的信息:

1.請求路徑(e.g.?/clients/1542,?/photos/list), 包含查詢字符串

2.HTTP 方法 (e.g.?GET,?POST, …).

路由是在可被編譯的conf/routes文件中被定義的。這意味著你可以在你的瀏覽器中直接看到路由的錯誤信息

依賴注入

Play支持生成兩種路由器的類型,一個是依賴注入路由器,另一個是靜態(tài)路由。默認(rèn)的是依賴注入路由器,這也是在Play種子Activator模板中的樣例,因此我們推薦你使用依賴注入Contrlller。如果你需要使用靜態(tài)Contrller,你可以通過在你的build.sbt配置文件里添加下面這樣的配置來轉(zhuǎn)換到靜態(tài)路由生成器:

routesGenerator:= StaticRoutesGenerator

在Play的文檔中的代碼樣例假定你使用了依賴注入路由生成器。如果你沒有使用這個,你可以容易的改寫代碼樣例到靜態(tài)路由生成器,既可以使用@符號在路由的Controller的調(diào)用部分加上前綴,或者通過聲明你的每一個Contrller為object而不是class。

路由文件的語法

conf/routes是路由器使用的配置文件。這個文件里出了應(yīng)用需要的所有的路由。每個路由由HTTP方法和URI模式組成,這兩個都與調(diào)用Action生成器相關(guān)。

讓我們來看一看路由定義的樣子:

GET? /clients/:idcontrollers.Clients.show(id: Long)

每一個路由以HTTP方法開始,下來是URI模式。最后一個元素是調(diào)用定義。

你也可以以#字符開頭在路由文件中增加注釋。

# Display a client.

GET ? ? /clients/:id? ? ? controllers.Clients.show(id: Long)

你可以通過一個特殊的前綴“->”,告訴路由文件使用一個不同的路由器:

->? ? ? /api? ? ? ? ? ? ? ? ? api.MyRouter

當(dāng)你和String Interpolating Routing DSL也被稱作SIRD路由整合時,或者當(dāng)你使用了多個路由文件的子項(xiàng)目時,這非常有用。

HTTP方法

HTTP方法可以使用任何被HTTP (GET,?PATCH,?POST,?PUT,?DELETE,?HEAD)支持的有效方法。

URI模式

URI模式定義了路由的請求路徑,請求路徑的部分可以是靜態(tài)的。

靜態(tài)路徑

例如,為了準(zhǔn)確的匹配到輸入的?GET /clients/all?請求,你可以定義這樣的路由:

GET? /clients/all? ? ? controllers.Clients.list()

動態(tài)路徑

如果你想定義一個通過ID檢索一個客戶的路由,你將需要增加一個動態(tài)的部分:

GET? /clients/:idcontrollers.Clients.show(id: Long)

注意:URI模式可能會有多個動態(tài)的部分。

動態(tài)部分的默認(rèn)匹配策略是通過正則表達(dá)式?[^/]+定義的,意思就是說任何一個定義為:id?的動態(tài)部分將嚴(yán)格的匹配一個URI路徑段。不像其他的模式類型,在路由中路徑段自動地URI-解碼,而是在傳遞給你的Controller之前,并在反向路由中解碼。

動態(tài)部分跨越多個/

如果你想讓動態(tài)部分可以捕獲多個通過正斜杠分割的URI路徑段,你可以使用語法*id(沒被稱為使用.*正則表達(dá)的通配符模式)定義動態(tài)部分:

GET ? ? /files/* ? namecontrollers.Application.download(name)

這個配置匹配像GET /files/images/logo.png樣的請求,動態(tài)部分name 將會捕捉到值images/logo.png?。

注意:跨越多個/的動態(tài)部分不會被路由器解碼也不會被反向路由器編碼。你的職責(zé)是驗(yàn)證任何用戶可能的輸入原生的URI段。反向路由器簡單的做一個字符串的連接,因此你將需要確保結(jié)果路徑是有效的,或不是,例如,含有多個前導(dǎo)斜桿或非ASCII字符。

自定義正則表達(dá)的動態(tài)部分

你也可以使用$id?語法為動態(tài)部分定義你自己的動態(tài)表達(dá)式:

GET? /items/$id<[0-9]+>? ? controllers.Items.show(id: Long)

就像通配符路由一樣,參數(shù)不會被路由器編碼或反向路由器解碼。你的職責(zé)是驗(yàn)證輸入,確保它在這個環(huán)境下的意義。

調(diào)用Action生成器方法

路由定義的最后一部分是調(diào)用。這部分必須定義一個有效的調(diào)用到一個返回?play.api.mvc.Action?值的方法,通常情況下是一個Controller的Action方法。

如果方法沒有定義任何參數(shù),僅使用完全限定的方法名:

GET? /? ? ? ? ? ? ? ? ? ? controllers.Application.homePage()

如果Action方法定義了一些參數(shù),所有這些參數(shù)的值將會在請求的URI中搜索,要么從URI路徑本身提取,要么從查詢字符串中。

# 從路徑中提取page參數(shù)

GET? /:page? ? ? ? ? ? controllers.Application.show(page)

或者:

# 從查詢字符串中提取頁面參數(shù)

GET ???/ ? ? controllers.Application.show(page)??

相應(yīng)的,在controllers.Application?Controller中定義show方法:

def show(page: String) = Action {

loadContentFromDatabase(page).map { htmlContent =>

Ok(htmlContent).as("text/html")

}.getOrElse(NotFound)

}

參數(shù)類型

對于String類型的參數(shù),輸入?yún)?shù)是可以選的。如果你想讓Play把傳入的參數(shù)轉(zhuǎn)換成特殊的Scala類型,你可以指定參賽類型:

GET? /clients/:idcontrollers.Clients.show(id: Long)

在?controllers.Clients?Controller中相應(yīng)的實(shí)現(xiàn)一個相同的show方法定義:

def show(id: Long) = Action {

Client.findById(id).map { client =>

Ok(views.html.Clients.display(client))

}.getOrElse(NotFound)

}

固定值的參數(shù)

有時你想為參數(shù)使用一個固定的值:

# Extract the page parameter from the path, or fix the value for /

GET? /? ? ? ? ? ? controllers.Application.show(page = "home")

GET? /:page? ? ? ? ? ? ? ? controllers.Application.show(page)

帶有默認(rèn)值的參數(shù)

在傳入的請求沒有找到值的時候,你也可以提供一個默認(rèn)值:

# Pagination links, like /clients?page=3

GET /clients controllers.Clients.list(page: Int ?=?1)

Optional類型的參數(shù)

你也可以指定一個不需要在所有的請求中都出現(xiàn)的Optional類型的參數(shù):

# The version parameter is optional. E.g. /api/list-all?version=3.0

GET /api/list-all controllers.Api.list(version: Option[String])

路由的優(yōu)先級

許多路由可以匹配到相同的請求,如果有沖突,第一個路由(按聲明的順序)被使用。

反轉(zhuǎn)路由

路由器也可以被用來從Scala調(diào)用內(nèi)部生成URL。這讓在一個單獨(dú)的配置文件中集中所有的URI模式成為可能,因此你在重構(gòu)你的應(yīng)用是會更加自信。

對于路由文件中的每一個使用的Controller,路由器會在routes包中生成一個有相同簽名的相同Action方法的‘Reverse Controller’,但是返回play.api.mvc.Call?而不是play.api.mvc.Action.

例如,如果你創(chuàng)建一個這樣的Controller:

package controllers

import play.api._

import play.api.mvc._class

Application?extends?Controller?{ def hello(name: String) = Action { Ok("Hello "?+ name +?"!") } }

并且如果你在conf/routes文件中增加了映射:

# Hello action

GET ? ??/hello/:name? ? ?controllers.Application.hello(name)

然后你就可以使用controllers.routes.Application反轉(zhuǎn)Controller反轉(zhuǎn)URL到Action方法:

// Redirect to /hello/Bob

def helloBob = Action { Redirect(routes.Application.hello("Bob")) }

注意:每一個Controller包都有一個路由子包。因此Action controllers.admin.Application.hello?可以通過controllers.admin.routes.Application.hello(只要在路由文件中的這個路由之前沒有其他可匹配的生成路徑)被反轉(zhuǎn)。

反轉(zhuǎn)Action方法的原理很簡單:它拿到你的參數(shù),并在路由模式中替換它們。在路徑段(:foo)的例子中,值在替換完成之前解碼,對于正則模式和通配符模式,字符串在原始形態(tài)中被替換,因此值可以跨越多個段。確保當(dāng)你把這些組件傳遞給反轉(zhuǎn)路由時忘記了這些必須的組件,并避免傳遞無效的用戶輸入。

默認(rèn)的Controller

Play有一個提供了幾個有用的Action的默認(rèn)Controller,這些可以在路由文件中直接調(diào)用:

# Redirects to https://www.playframework.com/ with 303 See Other

?GET??/about controllers.Default.redirect(to?="https://www.playframework.com/")

# Responds with 404 Not Found

?GET??/orders controllers.Default.notFound

# Responds with 500 Internal Server Error

?GET??/clients controllers.Default.error

?# Responds with 501 Not Implemented

?GET??/posts controllers.Default.todo

在這個例子中,GET /?重定向到外部的站點(diǎn),但是它也可以重定向到其他的Action(如上面的例子中的/posts?)。

自定義路由

Play提供了一個 DSL 來定義嵌入的路由器,這個路由器被稱為?String Interpolating Routing DSL,或者簡寫為SIRD。這個DSL有很多用途,包括嵌入一個輕量級的Play服務(wù),提供自定義或更高級的路由功能給規(guī)范的Play應(yīng)用,在測試方面甩REST服務(wù)幾條街。

詳見String Interpolating Routing DSL

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評論 19 139
  • 內(nèi)置的HTTP路由器 這個路由器用于翻譯每一個接收到的HTTP請求到對應(yīng)的action(一個controller類...
    zerolinke閱讀 2,096評論 0 0
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,082評論 25 709
  • 本系列主要翻譯自《ASP.NET MVC Interview Questions and Answers 》- B...
    圣杰閱讀 7,675評論 3 32
  • 青石的噴泉不停地唱晚 蘆葦青草邊,一圍古箏山高水流 許是竹影婆娑 沉香裊裊,唉 這一個下午 . 當(dāng)炭火煮熟一壺玉竹...
    東山島高永川閱讀 413評論 0 1

友情鏈接更多精彩內(nèi)容