文件

§Play 2.5 遷移指南

這是從 Play 2.4 遷移到 Play 2.5 的指南。如果您需要從 Play 的較早版本遷移,則必須先遵循 Play 2.4 遷移指南

除了此頁面上的資訊之外,還有一些主題有更詳細的遷移資訊

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。有幾個原因

  1. Play 2.5 的內部程式碼廣泛使用 scala-java8-compat 函式庫,它僅支援 Scala 2.11。scala-java8-compat 具有許多 Scala 和 Java 8 類型的轉換,例如 Scala Future 和 Java CompletionStage。(您可能會發現此函式庫對您的程式碼也有用。)

  2. 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 進行重大變更

此外,還有許多小變更

§已不建議使用的 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.Assetscontrollers.Default 也是類別,儘管存在靜態等效項,但建議你使用類別版本。

§如何轉移

建議的解決方案是對你的所有控制器使用類別。InjectedRoutesGenerator 現在是預設值,因此路由檔案中的控制器假設為類別,而非物件。

如果你仍有靜態控制器,則可以使用 StaticRoutesGenerator(如上所述),並在 routes 檔案中的路由前面加上 @ 符號,例如

GET  /assets/*file  @controllers.ExternalAssets.at(path = "/public", file)

§已過時的 play.Play 和 play.api.Play 方法

下列方法已在 play.Play 中過時

同樣地,play.api.Play 中採用隱式 Application 並委派給 Application 的方法(例如 def classloader(implicit app: Application))現在已過時。

§如何遷移

這些方法委派給 play.Applicationplay.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/jsonapplication/x-www-form-urlencoded。現在,預設會在沒有 charset 的情況下傳送 Content-Type。這同時適用於使用 WS 傳送要求和從 Play 動作傳回回應。如果您有非規範相容的客戶端或伺服器需要您傳送 charset 參數,您可以明確設定 Content-Type 標頭。

§Guice injector 和 Guice builder 變更

預設情況下,Guice 可以透過代理循環中的介面來解決循環相依性。由於循環相依性通常是程式碼異味,而且您也可以注入提供者來打破循環,因此我們選擇在預設的 Guice 注入器中停用此功能。其他 DI 架構也不太可能具有此功能,因此在撰寫 Play 模組時可能會導致問題。

現在 Guice 建構函式(GuiceInjectorBuilderGuiceApplicationBuilder)上有四個新方法,用於自訂 Guice 如何注入您的類別
* disableCircularProxies:停用上述代理介面以解決循環相依性的行為。若要允許代理,請使用 disableCircularProxies(false)
* requireExplicitBindings:指示注入器僅注入在模組中明確繫結的類別。這在測試繫結時很有用。
* requireAtInjectOnConstructors:需要使用 @Inject 註解的建構函式來建立類別實體。
* requireExactBindingAnnotations:停用 Guice 中容易出錯的功能,在注入 @Named(“foo”) Foo 時,它可以替換 @Named Foo 的繫結。

§CSRF 變更

為了讓 Play 的 CSRF 過濾器更能抵禦瀏覽器外掛程式的漏洞和新的擴充功能,CSRF 過濾器的預設組態已變得更為保守。變更包括

有一個新的組態選項,可以繞過對具有特定標頭的要求的新 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 取得。

如需更多詳細資料,請閱讀 JavaScala 的 CSRF 文件。

§Crypto 已過時

從 Play 1.x 開始,Play 就提供了一個 Crypto 物件,可提供一些加密操作。Play 內部使用它。Crypto 物件未在文件說明中提及,但 scaladoc 中將其稱為「加密工具程式」。

由於各種原因,提供加密工具程式作為一種便利性已證明不可行。在 2.5.x 中,Play 特定的功能已拆分為 CookieSignerCSRFTokenSignerAESSigner 特性,並已棄用 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

§sendFilesendPathsendResource 方法的變更

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 內嵌

換句話說,他們在傳送檔案時混合了 inlineattachment 模式。現在,在傳送檔案時,路徑和資源會將 inline 作為預設行為。當然,您可以使用這些方法中存在的參數在這兩種模式之間交替。

接下來:串流遷移指南


在此文件檔中發現錯誤?此頁面的原始碼可以在 這裡 找到。在閱讀 文件檔指南 後,請隨時提交拉取請求。有問題或建議要分享嗎?請前往 我們的社群論壇 與社群展開對話。