§處理結果
§變更預設的 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 部分內容
。它也會傳回傳送 Result
的 Accept-Ranges: bytes
。
注意:除了執行一些剖析以更好地處理多個範圍之外,
multipart/byteranges
尚未獲得完全支援。
範圍結果可以針對 Source
、InputStream
、檔案和 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)
)
在此文件中發現錯誤?此頁面的原始程式碼可以在 這裡 找到。在閱讀 文件準則 後,請隨時提交拉取請求。有問題或建議要分享嗎?前往 我們的社群論壇 與社群展開對話。