§操作结果
§更改默认 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)。
字符集用于将文本响应转换为相应的字节以通过网络套接字发送,以及使用适当的 ;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 Partial Content
。它还会为提供的 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)
)
下一步:会话和闪存作用域
发现此文档中的错误?此页面的源代码可以在 此处 找到。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?请访问 我们的社区论坛,与社区展开讨论。