文档

§操作结果

§更改默认 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 尚未完全支持。

可以为 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)
)

下一步:会话和闪存作用域


发现此文档中的错误?此页面的源代码可以在 此处 找到。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?请访问 我们的社区论坛,与社区展开讨论。