文件

§處理結果

§變更預設的 Content-Type

結果內容類型會自動從您指定為回應主體的 Scala 值推斷出來。

例如

val textResult = Ok("Hello World!")

會自動將 Content-Type 標頭設定為 text/plain,而

val xmlResult = Ok(<message>Hello World!</message>)

會將 Content-Type 標頭設定為 application/xml

提示:這是透過 play.api.http.ContentTypeOf 類型類別來完成的。

這很有用,但有時您會想要變更它。只要對結果使用 as(newContentType) 方法,就能建立一個具有不同 Content-Type 標頭的新類似結果

val htmlResult = Ok(<h1>Hello World!</h1>).as("text/html")

甚至更好,使用

val htmlResult2 = Ok(<h1>Hello World!</h1>).as(HTML)

注意:使用 HTML 而非 "text/html" 的好處在於,字元集會自動為您處理,而實際的 Content-Type 標頭會設定為 text/html; charset=utf-8。我們將稍後看到

§處理 HTTP 標頭

您也可以將任何 HTTP 標頭新增(或更新)至結果

val result = Ok("Hello World!").withHeaders(CACHE_CONTROL -> "max-age=3600", ETAG -> "xx")

請注意,設定 HTTP 標頭會自動捨棄先前值(如果存在於原始結果中)。

§設定和捨棄 Cookie

Cookie 只是 HTTP 標頭的一種特殊形式,但我們提供了一組輔助程式,讓操作更輕鬆。

您可以使用以下方式輕鬆將 Cookie 新增至 HTTP 回應

val result = Ok("Hello world")
  .withCookies(Cookie("theme", "blue"))
  .bakeCookies()

此外,要捨棄先前儲存在 Web 瀏覽器的 Cookie

val result2 = result.discardingCookies(DiscardingCookie("theme"))

您也可以設定和移除 Cookie 作為同一回應的一部分

val result3 = result.withCookies(Cookie("theme", "blue")).discardingCookies(DiscardingCookie("skin"))

§變更文字為基礎的 HTTP 回應的字元集

對於基於文字的 HTTP 回應,正確處理字元集非常重要。Play 會為您處理這部分,並預設使用 utf-8(請參閱 為何使用 utf-8)。

字元集用於將文字回應轉換為相應的位元組,以透過網路 Socket 傳送,並使用適當的 ;charset=xxx 延伸項目更新 Content-Type 標頭。

字元集會透過 play.api.mvc.Codec 類型類別自動處理。只要在當前範圍內匯入 play.api.mvc.Codec 的隱式實例,就能變更所有作業將使用的字元集

class Application @Inject() (cc: ControllerComponents) extends AbstractController(cc) {
  implicit val myCustomCharset: Codec = Codec.javaSupported("iso-8859-1")

  def index = Action {
    Ok(<h1>Hello World!</h1>).as(HTML)
  }
}

在此,由於範圍內有一個隱式字元集值,因此 Ok(...) 方法將使用它來將 XML 訊息轉換為 ISO-8859-1 編碼的位元組,並產生 text/html; charset=iso-8859-1 Content-Type 標頭。

現在,如果您想知道 HTML 方法如何運作,以下是它的定義

def HTML(implicit codec: Codec) = {
  "text/html; charset=" + codec.charset
}

如果您需要以一般方式處理字元集,可以在 API 中執行相同的動作。

§範圍結果

Play 支援 RFC 7233 的一部分,其中定義範圍要求和部分回應的運作方式。如果要求中存在可滿足的 Range 標頭,它會讓您傳送 206 部分內容。它也會傳回傳送 ResultAccept-Ranges: bytes

注意:除了執行一些剖析以更好地處理多個範圍之外,multipart/byteranges 尚未獲得完全支援。

範圍結果可以針對 SourceInputStream、檔案和 Path 產生。請參閱 RangeResult API 文件,以查看所有可用的方法。例如

val input          = getInputStream()
val partialContent = RangeResult.ofStream(input, request.headers.get(RANGE), "video.mp4", Some("video/mp4"))

或者對於 Source

val header  = request.headers.get(RANGE)
val content = "This is the full body!"
val source  = Source.single(ByteString(content))

val partialContent = RangeResult.ofSource(
  entityLength = content.length,
  source = source,
  rangeHeader = header,
  fileName = Some("file.txt"),
  contentType = Some(TEXT)
)

當請求的 Range 無法滿足時,例如,請求的 Range 標頭欄位中的範圍未與所選資源的目前範圍重疊,則會傳回 HTTP 狀態 416(範圍無法滿足)。

也可以預先搜尋 Source 的特定位置,以更有效率地傳送範圍結果。為此,您可以提供一個函式,其中會執行預先搜尋

val header  = request.headers.get(RANGE)
val content = "This is the full body!"
val source  = sourceFrom(content)

val partialContent = RangeResult.ofSource(
  entityLength = Some(content.length.toLong),
  getSource = (offset: Long) => (offset, source.drop(offset)),
  rangeHeader = header,
  fileName = Some("file.txt"),
  contentType = Some(TEXT)
)

下一步:Session 和 Flash 範圍


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