§Play 2.5 遷移指南
這是從 Play 2.4 遷移到 Play 2.5 的指南。如果您需要從 Play 的較早版本遷移,則必須先遵循 Play 2.4 遷移指南。
除了此頁面上的資訊之外,還有一些主題有更詳細的遷移資訊
- 串流遷移指南 – 遷移到 Akka 串流,現在在許多 Play API 中取代迭代器
- Java 遷移指南 - 遷移 Java 應用程式。Play 現在對函式類型使用原生 Java 類型,並在 Java 中提供多個新的可自訂元件。
Lucidchart 也在 從 Play 2.3.x 升級到 Play 2.5.x 上撰寫了一篇內容豐富的部落格文章。
§如何遷移
在 sbt 中載入/執行 Play 專案之前,需要執行下列步驟來更新您的 sbt 建置。
§Play 升級
更新 project/plugins.sbt 中的 Play 版本號碼以升級 Play
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.x")
其中 2.5.x
中的「x」是您要使用的 Play 次要版本,例如 2.5.0
。
§sbt 升級至 0.13.11
儘管 Play 2.5 仍可搭配 sbt 0.13.8 使用,但我們建議升級至最新 sbt 版本 0.13.11。sbt 的 0.13.11 版本包含許多 改進和錯誤修正。
更新您的 project/build.properties
,使其讀取
sbt.version=0.13.11
§Play Slick 升級
如果您的專案使用 Play Slick,您需要升級它
libraryDependencies += "com.typesafe.play" %% "play-slick" % "2.0.0"
或
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-slick" % "2.0.0",
"com.typesafe.play" %% "play-slick-evolutions" % "2.0.0"
)
§Play Ebean 升級
如果您的專案使用 Play Ebean,您需要升級它
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.0")
§ScalaTest + Play 升級
如果您的專案使用 ScalaTest + Play,您需要升級它
libraryDependencies ++= Seq(
"org.scalatestplus.play" %% "scalatestplus-play" % "1.5.1" % "test"
)
§Scala 2.10 支援已終止
Play 2.3 和 2.4 同時支援 Scala 2.10 和 2.11。Play 2.5 已終止對 Scala 2.10 的支援,現在僅支援 Scala 2.11。有幾個原因
-
Play 2.5 的內部程式碼廣泛使用 scala-java8-compat 函式庫,它僅支援 Scala 2.11。scala-java8-compat 具有許多 Scala 和 Java 8 類型的轉換,例如 Scala
Future
和 JavaCompletionStage
。(您可能會發現此函式庫對您的程式碼也有用。) -
Play 的下一個版本可能會新增對 Scala 2.12 的支援。現在是 Play 轉移到 Scala 2.11 的時候了,這樣即將到來的 2.12 轉換會更容易。
§如何遷移
Scala 和 Java 使用者都必須設定 sbt 以使用 Scala 2.11。即使專案中沒有 Scala 程式碼,Play 本身使用 Scala,且必須設定為使用正確的 Scala 函式庫。
若要在 sbt 中設定 Scala 版本,只需設定 scalaVersion
鍵,例如
scalaVersion := "2.11.8"
如果您有一個單一專案建置,則此設定可以單獨放在 build.sbt
中。但是,如果您有多個專案建置,則必須在每個專案中設定 Scala 版本設定。通常,在多個專案建置中,您會有一些由每個專案共用的設定,這是放置設定的最佳位置,例如
def common = Seq(
scalaVersion := "2.11.8"
)
lazy val projectA = (project in file("projectA"))
.enablePlugins(PlayJava)
.settings(common: _*)
lazy val projectB = (project in file("projectB"))
.enablePlugins(PlayJava)
.settings(common: _*)
§變更至 Logback 設定
作為移除 Play 對 Logback 的硬編碼相依性的變更的一部分 (請參閱重點),Logback 設定使用的其中一個類別必須移至另一個套件。
§如何遷移
您需要更新 Logback 設定檔 (logback*.xml
),並將對舊 play.api.Logger$ColoredLevel
的任何參照變更為新的 play.api.libs.logback.ColoredLevel
類別。
變更後的新設定會類似這樣
<conversionRule conversionWord="coloredLevel"
converterClass="play.api.libs.logback.ColoredLevel" />
如果您使用編譯時相依性注入,您需要將應用程式載入器從使用 Logger.configure(...)
變更為下列內容
LoggerConfigurator(context.environment.classLoader).foreach { _.configure(context.environment) }
您可以在文件中的 設定記錄 區段中找到更多有關如何設定 Play 與不同記錄架構的詳細資訊。
§Play WS 升級至 AsyncHttpClient 2
Play WS 已升級為使用 AsyncHttpClient 2。這是一個重大升級,使用 Netty 4.0。AHC 2.0 中的大部分變更都隱藏在幕後,但 AHC 有些重要的重構,需要對 WS API 進行重大變更
AsyncHttpClientConfig
已替換為DefaultAsyncHttpClientConfig
。allowPoolingConnection
和allowSslConnectionPool
在 AsyncHttpClient 中已合併為單一keepAlive
變數。因此,play.ws.ning.allowPoolingConnection
和play.ws.ning.allowSslConnectionPool
無效,如果進行設定,將會擲回例外。webSocketIdleTimeout
已移除,因此在AhcWSClientConfig
中不再可用。ioThreadMultiplier
已移除,因此在AhcWSClientConfig
中不再可用。FluentCaseInsensitiveStringsMap
類別已移除,並替換為 Netty 的HttpHeader
類別。Realm.AuthScheme.None
已移除,因此在WSAuthScheme
中不再可用。
此外,還有許多小變更
- 為了反映適當的 AsyncHttpClient 程式庫名稱,套件
play.api.libs.ws.ning
已重新命名為play.api.libs.ws.ahc
,而Ning*
類別已重新命名為Ahc*
。此外,AHC 設定已變更為play.ws.ahc
前綴,例如play.ws.ning.maxConnectionsPerHost
現在為play.ws.ahc.maxConnectionsPerHost
。 - 已移除不建議使用的介面
play.libs.ws.WSRequestHolder
。 play.libs.ws.play.WSRequest
介面現在傳回java.util.concurrent.CompletionStage
,而非F.Promise
。- 仰賴
Play.current
或Play.application
的靜態方法已不建議使用。 - Play WS 會從內容類型推斷字元集,並在請求的
Content-Type
標頭中附加字元集(如果尚未設定)。這造成一些混淆和錯誤,因此在 2.5.x 中,Content-Type
標頭不會自動包含推斷的字元集。如果您明確設定Content-Type
標頭,設定會照常生效。
§已不建議使用的 GlobalSettings
作為持續努力擺脫 Play 中的整體狀態的一部分,GlobalSettings
和應用程式的 Global
物件已不建議使用。如需更多詳細資訊,請參閱 Play 2.4 遷移指南,了解如何遷移並不再使用 GlobalSettings
。
§已移除的 Plugins API
Plugins API 已在 Play 2.4 中不建議使用,並已在 Play 2.5 中移除。Plugins API 已被 Play 的相依性注入和模組系統取代,提供更簡潔且更彈性的方式來建置可重複使用的元件。如需如何從外掛程式遷移至相依性注入的詳細資訊,請參閱 Play 2.4 遷移指南。
§使用 InjectedRoutesGenerator 產生的路由
路由現在使用相依性注入感知的 InjectedRoutesGenerator
產生,而非先前的 StaticRoutesGenerator
,後者假設控制器是單例物件。
若要復原到較早的行為(例如,你的程式碼中有「object MyController」),請將下列程式碼行加入你的 build.sbt
檔案
routesGenerator := StaticRoutesGenerator
如果你使用 Build.scala
而非 build.sbt
,則需要匯入 routesGenerator
設定金鑰
import play.sbt.routes.RoutesCompiler.autoImport._
使用靜態路由產生器的靜態控制器並未過時,但建議你轉移到使用具有依賴性注入的類別。
§已使用依賴性注入取代靜態控制器
controllers.ExternalAssets
現在是一個類別,且沒有靜態等效項。controllers.Assets
和 controllers.Default
也是類別,儘管存在靜態等效項,但建議你使用類別版本。
§如何轉移
建議的解決方案是對你的所有控制器使用類別。InjectedRoutesGenerator
現在是預設值,因此路由檔案中的控制器假設為類別,而非物件。
如果你仍有靜態控制器,則可以使用 StaticRoutesGenerator
(如上所述),並在 routes
檔案中的路由前面加上 @
符號,例如
GET /assets/*file @controllers.ExternalAssets.at(path = "/public", file)
§已過時的 play.Play 和 play.api.Play 方法
下列方法已在 play.Play
中過時
public static Application application()
public static Mode mode()
public static boolean isDev()
public static boolean isProd()
public static boolean isTest()
同樣地,play.api.Play
中採用隱式 Application
並委派給 Application 的方法(例如 def classloader(implicit app: Application)
)現在已過時。
§如何遷移
這些方法委派給 play.Application
或 play.Environment
,使用它們的程式碼應使用依賴注入來注入相關類別。
您應參閱 Play 2.4 遷移指南 中的依賴注入元件清單,以遷移內建 Play 元件。
例如,以下程式碼將環境和組態注入 Scala 中的控制器
class HomeController @Inject() (environment: play.api.Environment,
configuration: play.api.Configuration)
extends Controller {
def index = Action {
Ok(views.html.index("Your new application is ready."))
}
def config = Action {
Ok(configuration.underlying.getString("some.config"))
}
def count = Action {
val num = environment.resource("application.conf").toSeq.size
Ok(num.toString)
}
}
§處理舊元件
一般來說,您使用的元件不應依賴於整個應用程式,但有時您必須處理需要依賴於整個應用程式的舊元件。您可以透過將應用程式注入到其中一個元件中來處理這個問題
class FooController @Inject() (appProvider: Provider[Application])
extends Controller {
implicit lazy val app = appProvider.get()
def bar = Action {
Ok(Foo.bar(app))
}
}
請注意,通常您會想在這種情況下使用 Provider[Application]
來避免循環依賴。
更好的方法是,您可以建立自己的 *Api
類別,將靜態方法轉換為實例方法
class FooApi @Inject() (appProvider: Provider[Application]) {
implicit lazy val app = appProvider.get()
def bar = Foo.bar(app)
def baz = Foo.baz(app)
}
這讓您可以受益於 DI 提供的可測試性,並仍然使用使用全域狀態的函式庫。
§Content-Type charset 變更
在 Play 2.5 之前,Play 會將 charset
參數新增到未定義 charset 參數的特定內容類型,特別是 application/json
和 application/x-www-form-urlencoded
。現在,預設會在沒有 charset 的情況下傳送 Content-Type
。這同時適用於使用 WS
傳送要求和從 Play 動作傳回回應。如果您有非規範相容的客戶端或伺服器需要您傳送 charset 參數,您可以明確設定 Content-Type
標頭。
§Guice injector 和 Guice builder 變更
預設情況下,Guice 可以透過代理循環中的介面來解決循環相依性。由於循環相依性通常是程式碼異味,而且您也可以注入提供者來打破循環,因此我們選擇在預設的 Guice 注入器中停用此功能。其他 DI 架構也不太可能具有此功能,因此在撰寫 Play 模組時可能會導致問題。
現在 Guice 建構函式(GuiceInjectorBuilder
和 GuiceApplicationBuilder
)上有四個新方法,用於自訂 Guice 如何注入您的類別
* disableCircularProxies
:停用上述代理介面以解決循環相依性的行為。若要允許代理,請使用 disableCircularProxies(false)
。
* requireExplicitBindings
:指示注入器僅注入在模組中明確繫結的類別。這在測試繫結時很有用。
* requireAtInjectOnConstructors
:需要使用 @Inject 註解的建構函式來建立類別實體。
* requireExactBindingAnnotations
:停用 Guice 中容易出錯的功能,在注入 @Named(“foo”) Foo 時,它可以替換 @Named Foo 的繫結。
§CSRF 變更
為了讓 Play 的 CSRF 過濾器更能抵禦瀏覽器外掛程式的漏洞和新的擴充功能,CSRF 過濾器的預設組態已變得更為保守。變更包括
- 不再將
POST
要求列入黑名單,現在只有GET
、HEAD
和OPTIONS
要求會列入白名單,所有其他要求都需要 CSRF 檢查。這表示現在會檢查DELETE
和PUT
要求。 - 不再將
application/x-www-form-urlencoded
、multipart/form-data
和text/plain
要求列入黑名單,所有內容類型的要求,包括沒有內容類型,都需要 CSRF 檢查。這會導致一個後果,就是使用application/json
的 AJAX 要求現在需要在Csrf-Token
標頭中包含有效的 CSRF 令牌。 - 預設情況下會停用無狀態標頭繞過,例如
X-Requested-With
。
有一個新的組態選項,可以繞過對具有特定標頭的要求的新 CSRF 保護。這個組態選項在預設情況下會針對 Cookie 和 Authorization 標頭啟用,因此通常不使用階段驗證的 REST 程式客戶端,仍然可以在不傳送 CSRF 令牌的情況下運作。
不過,由於組態選項允許傳送所有不具有這些標頭的要求,因此使用其他驗證機制的應用程式(NTLM、TLS 伺服器端憑證)會容易受到 CSRF 攻擊。這些應用程式應該停用組態選項,讓它們經過驗證(無 Cookie)的要求受到 CSRF 篩選器的保護。
最後,已新增一個額外的選項,可以停用 CORS 篩選器所信任來源的 CSRF 檢查。請注意,CORS 篩選器必須在您的篩選器鏈中出現在 CSRF 篩選器之前,才能運作!
可以透過將下列組態新增到 application.conf
來還原 Play 的舊預設行為
play.filters.csrf {
header {
bypassHeaders {
X-Requested-With = "*"
Csrf-Token = "nocheck"
}
protectHeaders = null
}
bypassCorsTrustedOrigins = false
method {
whiteList = []
blackList = ["POST"]
}
contentType.blackList = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]
}
§取得 CSRF 令牌
以前,可以在任何動作中從 HTTP 要求中擷取 CSRF 令牌。現在,您必須具備 CSRF 篩選器或 CSRF 動作,才能讓 CSRF.getToken
運作。如果您沒有使用篩選器,可以使用 Scala 中的 CSRFAddToken
動作或 Java 註解 AddCSRFToken
,以確保階段中有令牌。
此外,此版本已修正一個小錯誤,如果 CSRF 令牌的簽章無效,CSRF 令牌會是空的(在範本輔助程式中擲回例外)。現在,它會在同一個要求中重新產生,因此令牌仍然可以從範本輔助程式和 CSRF.getToken
取得。
如需更多詳細資料,請閱讀 Java 和 Scala 的 CSRF 文件。
§Crypto 已過時
從 Play 1.x 開始,Play 就提供了一個 Crypto
物件,可提供一些加密操作。Play 內部使用它。Crypto
物件未在文件說明中提及,但 scaladoc 中將其稱為「加密工具程式」。
由於各種原因,提供加密工具程式作為一種便利性已證明不可行。在 2.5.x 中,Play 特定的功能已拆分為 CookieSigner
、CSRFTokenSigner
和 AESSigner
特性,並已棄用 Crypto
單例物件。
§如何遷移
加密遷移將取決於您的使用案例,特別是在加密原語的結構不安全時。簡短的版本是,如果可能,請使用 Kalium,否則請使用 Tink 或直接使用 JCA。
請參閱 加密遷移 以取得更多詳細資訊。
§Netty 4 升級
Netty 已從 3.10 升級至 4.0。這其中一個後果是,用於設定 Netty 通道選項的設定選項已變更。完整的選項清單可以在 這裡 查看。
§如何遷移
修改任何 play.server.netty.option
金鑰以使用 ChannelOption 中定義的新金鑰。以下是部分較常使用的金鑰對應:
舊 | 新 |
---|---|
play.server.netty.option.backlog |
play.server.netty.option.SO_BACKLOG |
play.server.netty.option.child.keepAlive |
play.server.netty.option.child.SO_KEEPALIVE |
play.server.netty.option.child.tcpNoDelay |
play.server.netty.option.child.TCP_NODELAY |
§sendFile
、sendPath
和 sendResource
方法的變更
Java (play.mvc.StatusHeader
) 和 Scala (play.api.mvc.Results.Status
) API 以前具有下列行為
API | 方法 | 預設值 |
---|---|---|
Scala | play.api.mvc.Results.Status.sendResource |
內嵌 |
Scala | play.api.mvc.Results.Status.sendPath |
附件 |
Scala | play.api.mvc.Results.Status.sendFile |
附件 |
Java | play.mvc.StatusHeader.sendInputStream |
無 |
Java | play.mvc.StatusHeader.sendResource |
內嵌 |
Java | play.mvc.StatusHeader.sendPath |
附件 |
Java | play.mvc.StatusHeader.sendFile |
內嵌 |
換句話說,他們在傳送檔案時混合了 inline
和 attachment
模式。現在,在傳送檔案時,路徑和資源會將 inline
作為預設行為。當然,您可以使用這些方法中存在的參數在這兩種模式之間交替。
接下來:串流遷移指南
在此文件檔中發現錯誤?此頁面的原始碼可以在 這裡 找到。在閱讀 文件檔指南 後,請隨時提交拉取請求。有問題或建議要分享嗎?請前往 我們的社群論壇 與社群展開對話。