文件

§處理錯誤

HTTP 應用程式可以傳回兩種主要類型的錯誤 - 伺服器端錯誤和客戶端錯誤。客戶端錯誤表示連線的客戶端執行錯誤的動作,伺服器端錯誤表示伺服器端發生問題。

在許多情況下,Play 會自動偵測客戶端錯誤,這些錯誤包括格式錯誤的標頭值、不支援的內容類型,以及對找不到的資源的請求。在許多情況下,Play 也會自動處理伺服器錯誤,如果您的動作程式碼擲出例外,Play 會捕捉此例外,並產生伺服器錯誤頁面傳送給客戶端。

Play 處理這些錯誤的介面是 HttpErrorHandler。它定義了兩個方法,onClientErroronServerError

§在 JSON API 中處理錯誤

預設情況下,Play 以 HTML 格式傳回錯誤。
對於 JSON API,以 JSON 格式傳回錯誤會比較一致。

Play 提議一個替代的 HttpErrorHandler 實作,稱為 JsonHttpErrorHandler,它會傳回以 JSON 格式化的錯誤。

若要使用該 HttpErrorHandler 實作,您應該在 application.conf 中設定 play.http.errorHandler 組態屬性,如下所示

play.http.errorHandler = play.api.http.JsonHttpErrorHandler

§同時使用 HTML 和 JSON,以及其他內容類型

如果您的應用程式使用 HTML 和 JSON 的混合,就像在現代網路應用程式中很常見,Play 提供另一個錯誤處理常式,它會根據客戶端 Accept 標頭中指定的偏好設定,委派給 HTML 或 JSON 錯誤處理常式。這可以使用下列方式指定

play.http.errorHandler = play.api.http.HtmlOrJsonHttpErrorHandler

這是大多數應用程式的合適預設錯誤處理常式選項。

最後,如果您想除了 HTML 和 JSON 之外,還支援其他錯誤內容類型,您可以延伸 PreferredMediaTypeHttpErrorHandler,並指定自訂錯誤處理常式,如下所述。

§提供自訂錯誤處理常式

如果您使用 BuiltInComponents 來建構您的應用程式,請覆寫 httpErrorHandler 方法以傳回您的自訂處理常式的執行個體。

如果您使用執行時期依賴性注入(例如 Guice),則可以在執行時期動態載入錯誤處理常式。最簡單的方式是在根目錄中建立一個名為 ErrorHandler 的類別,並實作 HttpErrorHandler,例如

import javax.inject.Singleton

import scala.concurrent._

import play.api.http.HttpErrorHandler
import play.api.mvc._
import play.api.mvc.Results._

@Singleton
class ErrorHandler extends HttpErrorHandler {
  def onClientError(request: RequestHeader, statusCode: Int, message: String): Future[Result] = {
    Future.successful(
      Status(statusCode)("A client error occurred: " + message)
    )
  }

  def onServerError(request: RequestHeader, exception: Throwable): Future[Result] = {
    Future.successful(
      InternalServerError("A server error occurred: " + exception.getMessage)
    )
  }
}

如果您將錯誤處理常式放在根目錄(即無套件)中,並將其命名為 ErrorHandler,Play 會預設使用它。

但是,如果您想要

然後在 application.conf 中新增設定屬性 play.http.errorHandler,指向您的自訂錯誤處理常式類別

play.http.errorHandler = "com.example.ErrorHandler"

如果您想要針對客戶端偏好的媒體類型使用錯誤處理常式,並為另一種媒體類型新增自己的錯誤處理常式,您可以延伸 PreferredMediaTypeHttpErrorHandler

import javax.inject._

import play.api.http._

class MyHttpErrorHandler @Inject() (
    jsonHandler: JsonHttpErrorHandler,
    htmlHandler: DefaultHttpErrorHandler,
    textHandler: MyTextHttpErrorHandler
) extends PreferredMediaTypeHttpErrorHandler(
      "application/json" -> jsonHandler,
      "text/html"        -> htmlHandler,
      "text/plain"       -> textHandler
    )

上述範例使用 Play 預設的 JSON 和 HTML 處理常式,並新增一個自訂處理常式,如果客戶端偏好純文字,則會使用此處理常式,例如如果要求有 Accept: text/plain

§延伸預設錯誤處理常式

開箱即用,Play 的預設錯誤處理程式提供許多有用的功能。例如,在開發模式下,當伺服器錯誤發生時,Play 將嘗試找出並呈現應用程式中導致該例外狀況的程式碼片段,以便您能快速查看並找出問題。您可能想在生產環境中提供自訂伺服器錯誤,同時在開發環境中維持該功能。為了簡化此流程,Play 提供了一個 DefaultHttpErrorHandler,其中包含一些方便的方法,您可以覆寫這些方法,以便將自訂邏輯與 Play 的既有行為混合在一起。

例如,若要在生產環境中僅提供自訂伺服器錯誤訊息,讓開發錯誤訊息保持不變,而且您還想提供特定的禁止錯誤頁面

import javax.inject._

import scala.concurrent._

import play.api._
import play.api.http.DefaultHttpErrorHandler
import play.api.mvc._
import play.api.mvc.Results._
import play.api.routing.Router

@Singleton
class ErrorHandler @Inject() (
    env: Environment,
    config: Configuration,
    sourceMapper: OptionalSourceMapper,
    router: Provider[Router]
) extends DefaultHttpErrorHandler(env, config, sourceMapper, router) {
  override def onProdServerError(request: RequestHeader, exception: UsefulException) = {
    Future.successful(
      InternalServerError("A server error occurred: " + exception.getMessage)
    )
  }

  override def onForbidden(request: RequestHeader, message: String) = {
    Future.successful(
      Forbidden("You're not allowed to access this resource.")
    )
  }
}

查看 DefaultHttpErrorHandler 的完整 API 文件,以了解有哪些方法可供覆寫,以及如何利用這些方法。

接下來:非同步 HTTP 程式設計


在這個文件當中發現錯誤?此頁面的原始程式碼可以在 這裡 找到。在閱讀完 文件指南 之後,請隨時提出 pull request。有問題或建議想分享嗎?請前往 我們的社群論壇,與社群展開對話。