I am writing an application to provide files to the clients via a RESTful service for which I am using Akka HTTP.
The request from the client could be a POST request with the body containing the name of the file which I need to provide.
{filename: abc.zip}
I have the files stored on my server. How do I go about providing the file and what would be the appropriate Response type? The file could be of any format. In java, we specify it as MediaType.APPLICATION_OCTET_STREAM.
A barebone HTTP server for binary file download (with the target file located at src/main/resources/
) might look something like the following:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl._
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpEntity, ContentTypes}
import akka.http.scaladsl.server.Directives._
import java.nio.file.Paths
import scala.io.StdIn
object DownloadServer {
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
implicit val ec = system.dispatcher
val route =
path("hello") {
get {
complete( HttpEntity( ContentTypes.`text/html(UTF-8)`,
"Hello from Akka-HTTP!"
) )
}
} ~
path("download") {
post {
formField('filename) { filename: String =>
complete( HttpEntity( ContentTypes.`application/octet-stream`,
FileIO.fromPath(Paths.get(s"src/main/resources/$filename"), 100000)
) )
}
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine()
bindingFuture
.flatMap(_.unbind())
.onComplete(_ => system.terminate())
}
}
To test it out, just run the server and use cURL
on a command prompt like below:
curl -X GET http://localhost:8080/hello
// Hello from Akka-HTTP!
curl -d "filename=abc.zip" -X POST http://localhost:8080/download > abc1.zip
// % Total % Received % Xferd Average Speed Time Time Time Current
// Dload Upload Total Spent Left Speed
// 100 131k 0 131k 100 16 6914k 839 --:--:-- --:--:-- --:--:-- 6937k
[UPDATE]
Per questions in comment section, formField() is for extracting a single Form field in the request. You could also use entity(as[someType])
instead by replacing line formField('filename) ... =>
with the following:
entity(as[String]) { entity =>
val filename = entity.split("=").last
FileIO.fromPath(nioFilePath, chunkSize) allows you to provide a buffer size, which is 100,000 in the sample code. You could also create custom Akka Flow with Framing.delimiter()
for more complex requirement. More details can be found in relevant Akka doc .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.