模式匹配方式就会显得篇幅臃肿及模式僵化

时间:2022-06-12 08:29:19

  在上篇我们介绍了Akka-http Low-Level-Api。实际上这个Api供给了Server对进来的Http-requests进行措置惩罚惩罚及反响的自界说Flow或者转换函数的接入界面。我们看看下面官方文档给出的例子:

import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.model.HttpMethods._ import akka.http.scaladsl.model._ import akka.stream.ActorMaterializer import scala.io.StdIn object WebServer { def main(args: Array[String]) { implicit val system = ActorSystem() implicit val materializer = ActorMaterializer() // needed for the future map/flatmap in the end implicit val executionContext = system.dispatcher val requestHandler: HttpRequest => HttpResponse = { case HttpRequest(GET, Uri.Path("/"), _, _, _) => HttpResponse(entity = HttpEntity( ContentTypes.`text/html(UTF-8)`, "<html><body>Hello world!</body></html>")) case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => HttpResponse(entity = "PONG!") case HttpRequest(GET, Uri.Path("/crash"), _, _, _) => sys.error("BOOM!") case r: HttpRequest => r.discardEntityBytes() // important to drain incoming HTTP Entity stream HttpResponse(404, entity = "Unknown resource!") } val bindingFuture = Http().bindAndHandleSync(requestHandler, "localhost", 8080) println(s"Server online at :8080/\nPress RETURN to stop...") StdIn.readLine() // let it run until user presses return bindingFuture .flatMap(_.unbind()) // trigger unbinding from the port .onComplete(_ => system.terminate()) // and shutdown when done } }

  我们看到上面例子里的requestHandler函数用模式匹配方法对可能收到的HttpRequest进行了相关HttpResponse的对应。在对应的过程中可能还会按request要求进行一些Server真个运算作为例如Rest-Api这样的处事。不过对付大型的处事,模式匹配方法就会显得篇幅痴肥及模式僵化。Akka-http供给了一套routing DSL作为High-Level-Api的主要构成部分。用routing DSL取代Low-Level-Api的模式匹配方法可以更简练的体例HttpRequest到HttpResponse的转换处事,能更灵活高效的实现现代大型Rest-Api处事。routing DSL实现Rest-Api处事的方法是通过构建一个由组件Directives组合而成的多个多层三明治布局Route。Route是一个类型:

type Route = RequestContext ⇒ Future[RouteResult]

下面是个Route例子:

val route: Flow[HttpRequest, HttpResponse, NotUsed]= get { pathSingleSlash { complete(HttpEntity(ContentTypes.`text/html(UTF-8)`,"<html><body>Hello world!</body></html>")) } ~ path("ping") { complete("PONG!") } ~ path("crash") { sys.error("BOOM!") } }

在上期讨论的例子里我们可以这样使用route:

val futBinding: Future[Http.ServerBinding] = connSource.to { Sink.foreach{ connection => println(s"client address ${connection.remoteAddress}") // connection handleWith flow // connection handleWithSyncHandler syncHandler //connection handleWithAsyncHandler asyncHandler connection handleWith route }}.run()

handleWith(flow)的参数应该是Flow[HttpRequest,HttpResponse,_]才对呀?这个我们先看看RouteResult东西: 

/** * The result of handling a request. * * As a user you typically don‘t create RouteResult instances directly. * Instead, use the methods on the [[RequestContext]] to achieve the desired effect. */ sealed trait RouteResult extends javadsl.server.RouteResult object RouteResult { final case class Complete(response: HttpResponse) extends javadsl.server.Complete with RouteResult { override def getResponse = response } final case class Rejected(rejections: immutable.Seq[Rejection]) extends javadsl.server.Rejected with RouteResult { override def getRejections = rejections.map(r ⇒ r: javadsl.server.Rejection).toIterable.asJava } implicit def route2HandlerFlow(route: Route)(implicit routingSettings: RoutingSettings, parserSettings: ParserSettings, materializer: Materializer, routingLog: RoutingLog, executionContext: ExecutionContext = null, rejectionHandler: RejectionHandler = RejectionHandler.default, exceptionHandler: ExceptionHandler = null): Flow[HttpRequest, HttpResponse, NotUsed] = Route.handlerFlow(route) }

这里有个隐式转换route2HandlerFlow把Route转换成Flow[HttpRequest,HttpResponse,NotUsed],问题解决了。