我想知道如何使用 http4s 库处理多部分内容。
想象一个具有以下代码片段的服务(完整的要点在这里(:
case GET -> Root / "form" =>
Ok(
"""|<html>
|<body>
|<form method="post" action="/post" enctype="multipart/form-data">
| <input type="date" name="birthDate" placeholder="birthDate">
| <input type="file" name="dataFile">
| <input type="submit">
|</form></body></html>""".stripMargin).
withContentType(Some(`Content-Type`(`text/html`)))
case req @ POST -> Root / "post" => {
req.decode[Multipart[IO]] { m =>
Ok(
s"""Multipart DatanParts:${m.parts.length}
|${m.parts.map { case f: Part[IO] => { f.name + ", headers: " + f.headers.mkString(",")} }.mkString("n")}""".stripMargin)
}
}
如果我执行服务并填写相应的字段,我会得到如下所示的输出:
Multipart Data
Parts:2
Some(birthDate), headers: Content-Disposition: form-data; name="birthDate"
Some(dataFile), headers: Content-Disposition: form-data; name="dataFile";
filename="file.pdf",Content-Type: application/pdf
所以我知道如何获取有关零件的信息,这些零件是 Part[IO]
类型的元素,包含headers
和body
.
我想知道如何处理这些零件。例如,在这种情况下,我想打开文件并告知其长度。这样做的惯用方法是什么?
Part[IO]
的body
是一个可以使用fs2
库中的方法进行处理的Stream[F[_],Byte]
。
有几种可能性,一种可能性是使用 io.file.writeAll
和 io.file.writeAllASync
方法将流内容写入文件。
适用于基于字符串的文件的另一种可能性是使用 utf8Decode
方法处理流的内容。
结果可能是:
case req @ POST -> Root / "post" => {
req.decode[Multipart[IO]] { m => {
m.parts.find(_.name == Some("dataFile")) match {
case None => BadRequest(s"Not file")
case Some(part) => for {
contents <- part.body.through(utf8Decode).runFoldMonoid
response <- Ok(s"""Multipart DatanParts:${m.parts.length}
|File contents: ${contents}""".stripMargin)
} yield response
}
}
}
}
}
前面的代码段将返回文件的内容。