§處理錯誤
HTTP 應用程式可以傳回兩種主要類型的錯誤 - 伺服器端錯誤和客戶端錯誤。客戶端錯誤表示連線的客戶端執行錯誤的動作,伺服器端錯誤表示伺服器端發生問題。
在許多情況下,Play 會自動偵測客戶端錯誤,這些錯誤包括格式錯誤的標頭值、不支援的內容類型,以及對找不到的資源的請求。在許多情況下,Play 也會自動處理伺服器錯誤,如果您的動作程式碼擲出例外,Play 會捕捉此例外,並產生伺服器錯誤頁面傳送給客戶端。
Play 處理這些錯誤的介面是 HttpErrorHandler
。它定義了兩個方法,onClientError
和 onServerError
。
§在 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。有問題或建議想分享嗎?請前往 我們的社群論壇,與社群展開對話。