Обработка многокомпонентного контента в http4s
Я хотел бы знать, как я могу обрабатывать многокомпонентный контент, используя библиотеку 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 Data\nParts:${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
,
Я хотел бы знать, как обрабатывать эти детали. В этом случае, например, я хотел бы открыть файл и сообщить о его длине. Какой идиоматический способ сделать это?
1 ответ
body
из Part[IO]
это Stream[F[_],Byte]
которые могут быть обработаны с использованием методов из fs2
библиотека.
Существует несколько возможностей, одна из которых - записать содержимое потока в файл, используя 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 Data\nParts:${m.parts.length}
|File contents: ${contents}""".stripMargin)
} yield response
}
}
}
}
}
Предыдущий фрагмент вернет содержимое файла.