Akka-http针对Connection的两头都提供了方便编程的Api,分别是Server-Side-Api和Client-Side-Api。通过这两个Api可以大大提高编程效率。当然,上期我们提到过,Http-Server是Akka-http的核心部分,所有系统集成功能都是在Server-Side实现的。Akka-http-Server-Side-Api可以说是最先进的Http-Server编程工具,支持:

  • Full support for HTTP persistent connections
  • Full support for HTTP pipelining
  • Full support for asynchronous HTTP streaming including “chunked” transfer encoding accessible through an idiomatic API
  • Optional SSL/TLS encryption
  • WebSocket support

Server-Side-Api又分两个层次:Low-level-Server-Side-Api和High-level-Server-Side-Api。Low-level-server-api支持HTTP/1.1Server所有功能,包括:

  • Connection management
  • Parsing and rendering of messages and headers
  • Timeout management (for requests and connections)
  • Response ordering (for transparent pipelining support)

其它Server功能如请求解析request routing,文件服务file serving,数据压缩compression等都放在了High-level-server-api里。Akka-http是基于Akka-stream编写的,所以我们需要从Akka-stream运算模式来理解Akka-http的类型表现形式。

一个Http-Server是绑定在一个Socket上来接收客户端上传的request进行相关的服务提供的。Server对Socket的绑定在Akka-http里的可以Stream形式来表现:

val serverSource: Source[Http.IncomingConnection, Future[Http.ServerBinding]] =
Http().bind(interface = "localhost", port = )

Server-Side Socket绑定实际上就是一个Akka-stream-source:Source[IncomingConnection]:

  /**
* Creates a [[akka.stream.scaladsl.Source]] of [[akka.http.scaladsl.Http.IncomingConnection]] instances which represents a prospective HTTP server binding
* on the given `endpoint`.
*
* If the given port is 0 the resulting source can be materialized several times. Each materialization will
* then be assigned a new local port by the operating system, which can then be retrieved by the materialized
* [[akka.http.scaladsl.Http.ServerBinding]].
*
* If the given port is non-zero subsequent materialization attempts of the produced source will immediately
* fail, unless the first materialization has already been unbound. Unbinding can be triggered via the materialized
* [[akka.http.scaladsl.Http.ServerBinding]].
*
* If an [[ConnectionContext]] is given it will be used for setting up TLS encryption on the binding.
* Otherwise the binding will be unencrypted.
*
* If no `port` is explicitly given (or the port value is negative) the protocol's default port will be used,
* which is 80 for HTTP and 443 for HTTPS.
*
* To configure additional settings for a server started using this method,
* use the `akka.http.server` config section or pass in a [[akka.http.scaladsl.settings.ServerSettings]] explicitly.
*/
def bind(interface: String, port: Int = DefaultPortForProtocol,
connectionContext: ConnectionContext = defaultServerHttpContext,
settings: ServerSettings = ServerSettings(system),
log: LoggingAdapter = system.log)(implicit fm: Materializer): Source[Http.IncomingConnection, Future[ServerBinding]] = {
val fullLayer = fuseServerBidiFlow(settings, connectionContext, log) tcpBind(interface, choosePort(port, connectionContext), settings)
.map(incoming ⇒ {
val serverFlow = fullLayer.addAttributes(prepareAttributes(settings, incoming)) join incoming.flow
IncomingConnection(incoming.localAddress, incoming.remoteAddress, serverFlow)
})
.mapMaterializedValue(materializeTcpBind)
}

run这个Source[IncomingConnection]产生一串连接Connection:

  /**
* Represents one accepted incoming HTTP connection.
*/
final case class IncomingConnection(
localAddress: InetSocketAddress,
remoteAddress: InetSocketAddress,
flow: Flow[HttpResponse, HttpRequest, NotUsed]) { /**
* Handles the connection with the given flow, which is materialized exactly once
* and the respective materialization result returned.
*/
def handleWith[Mat](handler: Flow[HttpRequest, HttpResponse, Mat])(implicit fm: Materializer): Mat =
flow.joinMat(handler)(Keep.right).run() /**
* Handles the connection with the given handler function.
*/
def handleWithSyncHandler(handler: HttpRequest ⇒ HttpResponse)(implicit fm: Materializer): Unit =
handleWith(Flow[HttpRequest].map(handler)) /**
* Handles the connection with the given handler function.
*/
def handleWithAsyncHandler(handler: HttpRequest ⇒ Future[HttpResponse], parallelism: Int = )(implicit fm: Materializer): Unit =
handleWith(Flow[HttpRequest].mapAsync(parallelism)(handler))
}

IncomingConnection类型提供了个handleWith这样的streaming函数进行request到response的转换。用户可以下面的方式提供自定义的转换方法:

调用handleWith传入Flow[HttpRequest,HttpResponse,_],如:

  def req2Resp: HttpRequest => HttpResponse = _ => HttpResponse(entity=
HttpEntity(ContentTypes.`text/html(UTF-)`,"<h> Hello World! </h>"))
val flow = Flow.fromFunction(req2Resp)

提供HttpRequest=>HttpResponse函数传人handleWithSyncHandler:

def syncHandler: HttpRequest => HttpResponse = {
case HttpRequest(HttpMethods.GET,Uri.Path("/"),_headers,_entiy,_protocol) =>
HttpResponse(entity=
HttpEntity(ContentTypes.`text/html(UTF-)`,"<h> Hello World! </h>")) case req: HttpRequest =>
req.discardEntityBytes() // important to drain incoming HTTP Entity stream
HttpResponse(, entity = "Unknown resource!")
}

提供HttpRequest=>Future[HttpResponse]函数传人handleWithASyncHandler:

  def asyncHandler: HttpRequest => Future[HttpResponse] = {
case HttpRequest(HttpMethods.GET,Uri.Path("/"),_headers,_entiy,_protocol) => Future {
HttpResponse(entity=
HttpEntity(ContentTypes.`text/html(UTF-)`,"<h> Hello World! </h>")) } case req: HttpRequest => Future {
req.discardEntityBytes() // important to drain incoming HTTP Entity stream
HttpResponse(, entity = "Unknown resource!")
}
}

run Source[IncomingConnection,Future[ServerBinding]]返回结果为Future[ServerBinding]:

  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
}}.run()

我们可以通过ServerBinding来释放绑定的Socket:

 /**
* Represents a prospective HTTP server binding.
*
* @param localAddress The local address of the endpoint bound by the materialization of the `connections` [[akka.stream.scaladsl.Source]]
*
*/
final case class ServerBinding(localAddress: InetSocketAddress)(private val unbindAction: () ⇒ Future[Unit]) { /**
* Asynchronously triggers the unbinding of the port that was bound by the materialization of the `connections`
* [[akka.stream.scaladsl.Source]]
*
* The produced [[scala.concurrent.Future]] is fulfilled when the unbinding has been completed.
*/
def unbind(): Future[Unit] = unbindAction()
}

我们可以调用这个unbind():

  futBinding.flatMap(_.unbind())

整个示范源代码如下:

import akka.actor._
import akka.stream._
import akka.stream.scaladsl._
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import scala.concurrent._ object LowLevelServerApi extends App {
implicit val httpSys = ActorSystem("actorSystem")
implicit val httpMat = ActorMaterializer()
implicit val httpEc = httpSys.dispatcher val (interface,port) = ("localhost",)
val connSource: Source[Http.IncomingConnection,Future[Http.ServerBinding]] =
Http().bind(interface,port) def req2Resp: HttpRequest => HttpResponse = _ => HttpResponse(entity=
HttpEntity(ContentTypes.`text/html(UTF-)`,"<h> Hello World! </h>"))
val flow = Flow.fromFunction(req2Resp) def syncHandler: HttpRequest => HttpResponse = {
case HttpRequest(HttpMethods.GET,Uri.Path("/"),_headers,_entiy,_protocol) =>
HttpResponse(entity=
HttpEntity(ContentTypes.`text/html(UTF-)`,"<h> Hello World! </h>")) case req: HttpRequest =>
req.discardEntityBytes() // important to drain incoming HTTP Entity stream
HttpResponse(, entity = "Unknown resource!")
} def asyncHandler: HttpRequest => Future[HttpResponse] = {
case HttpRequest(HttpMethods.GET,Uri.Path("/"),_headers,_entiy,_protocol) => Future {
HttpResponse(entity=
HttpEntity(ContentTypes.`text/html(UTF-)`,"<h> Hello World! </h>")) } case req: HttpRequest => Future {
req.discardEntityBytes() // important to drain incoming HTTP Entity stream
HttpResponse(, entity = "Unknown resource!")
}
} 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
}}.run() println(s"Server running at $interface $port. Press any key to exit ...") scala.io.StdIn.readLine() futBinding.flatMap(_.unbind())
.onComplete(_ => httpSys.terminate()) }

Akka(29): Http:Server-Side-Api,Low-Level-Api的更多相关文章

  1. Identity Server 4 原理和实战(完结)_建立Identity Server 4项目,Client Credentials 授权实例

    创建项目 dotnet new -i IdentityServer4.Templates 多出来的这些模板 adminUI用来测试,想要用再生产环境,需要交钱 结合core的 Identity来使用 ...

  2. Scalaz(29)- Free :Coyoneda - Functor for free

    很多时候我们会遇到一些高阶类型F[_],但又无法实现它的map函数,也就是虽然形似但F不可能成为Functor.看看下面的例子: trait Interact[A] case class Ask(pr ...

  3. JMS生产者+单线程发送-我们到底能走多远系列(29)

    我们到底能走多远系列(29) 扯淡: “然后我俩各自一端/望着大河弯弯/终于敢放胆/嘻皮笑脸/面对/人生的难”      --- <山丘> “迎着风/迎向远方的天空/路上也有艰难/也有那解 ...

  4. Akka(2):Actor生命周期管理 - 监控和监视

    在开始讨论Akka中对Actor的生命周期管理前,我们先探讨一下所谓的Actor编程模式.对比起我们习惯的行令式(imperative)编程模式,Actor编程模式更接近现实中的应用场景和功能测试模式 ...

  5. Akka(33): Http:Marshalling,to Json

    Akka-http是一项系统集成工具.这主要依赖系统之间的数据交换功能.因为程序内数据表达形式与网上传输的数据格式是不相同的,所以需要对程序高级结构化的数据进行转换(marshalling or se ...

  6. Windows Phone开发(29):隔离存储C

    原文:Windows Phone开发(29):隔离存储C 本文是隔离存储的第三节,大家先喝杯咖啡放松,今天的内容也是非常简单,我们就聊一件东东--用户设置. 当然了,可能翻译为应用程序设置合适一些,不 ...

  7. Akka(6): become/unbecome:运算行为切换

    通过一段时间的学习了解,加深了一些对Akka的认识,特别是对于Akka在实际编程中的用途方面.我的想法,或者我希望利用Akka来达到的目的是这样的:作为传统方式编程的老兵,我们已经习惯了直线流程方式一 ...

  8. Akka(8): 分布式运算:Remoting-远程查找式

    Akka是一种消息驱动运算模式,它实现跨JVM程序运算的方式是通过能跨JVM的消息系统来调动分布在不同JVM上ActorSystem中的Actor进行运算,前题是Akka的地址系统可以支持跨JVM定位 ...

  9. Akka(0):聊聊对Akka的初步了解和想法

    前一段时间一直沉浸在函数式编程模式里,主要目的之一是掌握一套安全可靠的并发程序编程方法(concurrent programming),最终通过开源项目FunDA实现了单机多核CPU上程序的并行运算. ...

随机推荐

  1. 201521123015 《Java程序设计》第3周学习总结

    本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点. 书面作业 Q1.代码阅读 publi ...

  2. 201521123073 《Java程序设计》第12周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int age,doubl ...

  3. sublime text3 好用的插件!!!

    1.首先,你要保证sublime有Package Control,所以,如果没有,那么将Ctrl+`打开sublime控制台,将下列代码复制进去! import urllib.request,os; ...

  4. Java:参数数量可变的方法

    许多Java新人在看到下面的这段代码的时候,都会问一个问题:dealArray方法里那三个小点点是什么啊? [java] view plaincopy public class TestVarArgu ...

  5. java.lang.IllegalArgumentException: node to traverse cannot be null!

    查看HQL的语句是否写错了,是否有在From后面加空格.我就是没有加空格报了错误! return sessionFactory.getCurrentSession().createQuery(&quo ...

  6. 跨浏览器的placeholder – 原生JS版

    转自来源 : http://www.ifrans.cn/placehoder/ 跨浏览器的placeholder – 原生JS版 html5为input元素新增了一个属性”placeholder”,提 ...

  7. 框架应用:Mybatis (三) - 关系映射

    你有一张你自己的学生证?(一对一) 你这一年级有多少个学生?(一对多) 班上学生各选了什么课?(多对多) 两张表以上的操作都需要联立多张表,而用SQL语句可以直接联立两张表,用工程语言则需要手动完成这 ...

  8. JVM菜鸟进阶高手之路三

    转载请注明原创出处,谢谢! 笨神大大分享: 小程序里面搜索:JVMPocket,这个小程序是笨神大大提供的,里面可以搜索相关JVM参数,用法. -XX:MaxTenuringThreshold,这个参 ...

  9. Netty4 学习笔记之一:客户端与服务端通信 demo

    前言 因为以前在项目中使用过Mina框架,感受到了该框架的强大之处.于是在业余时间也学习了一下Netty.因为Netty的主要版本是Netty3和Netty4(Netty5已经被取消了),所以我就直接 ...

  10. AngularJS–Animations(动画)

    点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/   在AngularJS 1.3 中,给一些指令(eg:   ngRepeat,ngSw ...