施那些年喝了的鸡汤

 
我们说了Akka-http是一个吓之网融为一体工具,集成是由此数量交换方式贯彻之。Http是独在网上传和吸纳的正经协商。所以,在运用Akka-http之前,可能咱们或需要将Http模式的网上数据交换细节了解了解。数据交换双方是透过Http消息类型Request和Response来促成的。在Akka-http中对应之凡HttpRequest和HttpResponse。这片只类别且有所HttpEntity类型来装需要交换的数码。首先,无论如何数据在线上的表现形式肯定是一串bytes。所以,数据交换两头Request,Response中的Entity也必是坐bytes来表述的。在Akka-http里我们将要导的数目易成ByteString,通过网络发送給接收端、接收端再将吸收消息Entity中之ByteString转换成靶子项目的多寡。这片个转移过程就是是Akka-http的Marshalling和Unmarshalling过程了。我们先由HttpEntity的构建函数来了解它们的概念:

鸡汤

图片 1

图源自网络

鸡汤,这个于几年前就起来流行起来的歌词,早已不再是赖仅的鸡肉汤,它的内容基本上是励志主人公从一个无名小卒,通过大力,渐渐地成人生赢下的故事。

兹于简书、微信朋友围、微博还能来看它们的身形。

坐落女生身上,是颓废女主突然醒来,每天呆在图书馆不断长自己,同时展开各种走,最后甩掉土渣的表面,成为一个雅大方且能力高的爱妻。而男性更屌丝大翻身,通过减肥学习,最后迎娶白富美,走及人生巅峰。

尚记得自己高中的时节,经常看鸡汤来刺激自己,什么“20年度之女生为什么要大力”,“给大学生之同查封信”,“比你可以之丁较你再度努力”之类的。每次看了,热血沸腾,然后便以出一个本子开始举行详细的计划,从几接触交几触及,干啊事。

可现实也给民意痛,因为自己从未一样破就计划。比如计划早六点痊愈,然后花费一个钟头阅读,结果早上直接上床到了八点,于是后面的计划总体吹。

于计划没有就,成绩而跌时,我不怕开始怨恨自己之莫争气与懒惰,然后还要于网上检索鸡汤,结果形成一个恶性循环。

在扣押了不少的鸡汤之后,我逐渐发现了其中的套路,鸡汤内容大多是有的本来以杀又到底的口,通过同样多级努力化大富帅(白富美)的故事。因此,所谓的鸡汤还像是一样管辖短篇网络小说,小说的栋梁不也是各种打怪升级,一步步地爬上权力顶峰,成为人生赢下之吧?当自身看鸡汤时,就无形中将协调代入主角,仿佛已经经历了惨痛的煎熬,然后一举中标。原来心中之心腹,也是同样种幻想,这阵鸡血的持续时间短则一分钟,长则等同星期。我光是让主角的胜利光辉吸引,因此忽视了那些枯燥乏味的拼命。

骨子里仔细想想也了解,没有人会仅仅看几篇稿子,就获得持续的动力。那些坚持下去的口,往往发生好前进的靶子,他们了解好想使之未来。而扣押鸡汤,仅仅是知道了别人的奋斗史,它说到底未是属自己之。

object HttpEntity {
  implicit def apply(string: String): HttpEntity.Strict = apply(ContentTypes.`text/plain(UTF-8)`, string)
  implicit def apply(bytes: Array[Byte]): HttpEntity.Strict = apply(ContentTypes.`application/octet-stream`, bytes)
  implicit def apply(data: ByteString): HttpEntity.Strict = apply(ContentTypes.`application/octet-stream`, data)
  def apply(contentType: ContentType.NonBinary, string: String): HttpEntity.Strict =
    if (string.isEmpty) empty(contentType) else apply(contentType, ByteString(string.getBytes(contentType.charset.nioCharset)))
  def apply(contentType: ContentType, bytes: Array[Byte]): HttpEntity.Strict =
    if (bytes.length == 0) empty(contentType) else apply(contentType, ByteString(bytes))
  def apply(contentType: ContentType, data: ByteString): HttpEntity.Strict =
    if (data.isEmpty) empty(contentType) else HttpEntity.Strict(contentType, data)

  def apply(contentType: ContentType, contentLength: Long, data: Source[ByteString, Any]): UniversalEntity =
    if (contentLength == 0) empty(contentType) else HttpEntity.Default(contentType, contentLength, data)
  def apply(contentType: ContentType, data: Source[ByteString, Any]): HttpEntity.Chunked =
    HttpEntity.Chunked.fromData(contentType, data)
...

❤乌鸡汤

图片 2

图表源自网络

以及鸡汤相反,现在又起流行于乌鸡汤。

例如:

01|转角一般不见面赶上好,只会逢乞丐。
02|
你道要添加得精就发男生好?你当只要发生了钱好妹子就是自己贴上来了?你道学霸就可知找到好办事?我报告您吧,这些都是的确的!
03|
我随即张脸要遮住两独地方就到了!一处于是右半边脸,另一样处在是荒谬半止脸。
04|努力不自然成功,但切莫努力也十分自在。

还有同句子金星的大名鼎鼎乌鸡汤:“做人,就象是练倒立,总起坚持不停止的早晚,当您实际坚持不歇的时光,就想,脑袋下面或垫的是一个几上无雪的痰盂,你虽到底能再坚持一会儿。”

对照鸡汤励志式的正能量,乌鸡汤则还像是揭秘现实的负能量。

苟自己的见地是,鸡汤和乌鸡汤结合起来看才是极致美。

气短时喝一样人口鸡汤,暖暖冰凉的胃部;

得意忘形时喝一样丁乌鸡汤,冷冷沸腾的胸。

暨本,我上了大学,已经大少看鸡汤了。因为我知道,即使看还多鸡汤,不行动依然未见面产生成就。所以,我不再实行着地于网上搜寻鸡汤,而是将工夫还花费在求学及。当自身每天去操场跑步,每天坐50单单词,每天早睡早起时,我感觉到自己好像就是改成了鸡汤的中坚。

鸡汤好喝,但无要贪杯哦~

巴大家当年喝了的鸡汤没有白喝。^_^

特别明朗,HttpEntity可以划分点儿良接近,一种植是Strict类型的,它的data是ByteString。另一样栽是UniversalEntity类型,它的数额dataBytes是Source[ByteString,Any]。无论如何最终在线上的要么ByteString。HttpEntity的ContentType注明了传输数据格式,有:

object ContentTypes {
  val `application/json` = ContentType(MediaTypes.`application/json`)
  val `application/octet-stream` = ContentType(MediaTypes.`application/octet-stream`)
  val `text/plain(UTF-8)` = MediaTypes.`text/plain` withCharset HttpCharsets.`UTF-8`
  val `text/html(UTF-8)` = MediaTypes.`text/html` withCharset HttpCharsets.`UTF-8`
  val `text/xml(UTF-8)` = MediaTypes.`text/xml` withCharset HttpCharsets.`UTF-8`
  val `text/csv(UTF-8)` = MediaTypes.`text/csv` withCharset HttpCharsets.`UTF-8`

  // used for explicitly suppressing the rendering of Content-Type headers on requests and responses
  val NoContentType = ContentType(MediaTypes.NoMediaType)
}

专注:ContentType只是同一种备注,不影响线达数表达形式,线达的多寡永远是ByteString。但是,其中的application/octet-stream类型代表数量必须是Source[ByteString,Any]。我们下就是透过客户端的事例来喻HttpEntity。下面是一个客户端测试函数:

  def runService(request: HttpRequest, rentity: RequestEntity) = {
   val futResp = for {
     entity <- Future.successful(rentity)
     resp <- Http(sys).singleRequest(
       request.copy(entity = rentity)
     )
   } yield resp

   futResp
    .andThen {
      case Success(r@HttpResponse(StatusCodes.OK, _, entity, _)) =>
        entity.dataBytes.map(_.utf8String).runForeach(println)
      case Success(r@HttpResponse(code, _, _, _)) =>
        println(s"Download request failed, response code: $code")
        r.discardEntityBytes()
      case Success(_) => println("Unable to download rows!")
      case Failure(err) => println(s"Download failed: ${err.getMessage}")

    }
  }

咱只有待对这函数传入RequestEntity就得了解返回Response里Entity的广大细节了。首先我们渴求服务端发送一个纯字符串Hello
World。服务端代码如下:

 } ~ path("text") {
      get {
        complete("Hello World!")
      } ~

虽然complete(“Hello
World!”)有些迷糊,不过相应complete做了些字符串到ByteString的易。我们得从点这个runService函数得到印证。下面是这个事例的调用:

  val reqText = HttpRequest(uri = s"http://localhost:8011/text")
  runService(reqText,HttpEntity.Empty)
    .andThen{case _ => sys.terminate()}

自打出示的结果可以得出runService函数中之entity.dataBytes.map(_.utf8String)已经将ByteString转换成了String,也就是说服务器端发送的Entity里的数量是ByteString。

咱们重尝试着发送一些数給服务端,然后给服务端把结果通过response
entity返回来:

    } ~ path("text") {
      get {
        complete("Hello World!")
      } ~
        post {
          withoutSizeLimit {
            extractDataBytes { bytes =>
              val data = bytes.runFold(ByteString())(_ ++ _)
              onComplete(data) { t =>
                complete(t)
              }
            }
          }
        }

咱们看来服务端对request
entity的操作是坐ByteString进行的。客户端上污染一模一样差字符的request如下:

  val postText = HttpRequest(HttpMethods.POST,uri = s"http://localhost:8011/text")
  val uploadText = HttpEntity(
    ContentTypes.`text/plain(UTF-8)`,
    // transform each number to a chunk of bytes
    ByteString("hello world again")
  )
  runService(postText,uploadText)
    .andThen{case _ => sys.terminate()}

咱们得看来放上entity里的数额是ByteString。

我们理解Akka-http是依据Akka-Stream的,具备Reactive-Stream功能特色。下面我们就算示范一下如何开展stream的上传下载。首先定制一个Source:

  val numbers = Source.fromIterator(() =>
    Iterator.continually(Random.nextInt()))
    .map(n => ByteString(s"$n\n"))
  //make conform to withoutSizeLimit constrain
  val source = limitableByteSource(numbers)

服务端也是故HttpEntity来装这个Source然后透过HttpRequest传给客户端的:

  path("random") {
      get {
        complete(
          HttpEntity(
            ContentTypes.`application/octet-stream`,
            // transform each number to a chunk of bytes
            source.take(10000)
          )
        )
      } ~

咱于客户端还是用runService来分析传过来的entity。由于接到一个特大型的Source,所以需要改一下接方式代码:

   futResp
    .andThen {
      case Success(r@HttpResponse(StatusCodes.OK, _, entity, _)) =>
        val futEnt = entity.dataBytes.map(_.utf8String).runForeach(println)
             Await.result(futEnt, Duration.Inf) // throws if binding fails
             println("End of stream!!!")
      case Success(r@HttpResponse(code, _, _, _)) =>
        println(s"Download request failed, response code: $code")
        r.discardEntityBytes()
      case Success(_) => println("Unable to download rows!")
      case Failure(err) => println(s"Download failed: ${err.getMessage}")

    }

之所以底的艺术调用:

  val reqRandom = HttpRequest(uri = s"http://localhost:8011/random")
    runService(reqRandom,HttpEntity.Empty)
     .andThen{case _ => sys.terminate()}

还示范一下每当客户端用Source上污染数。服务端代码:

       post {
          withoutSizeLimit {
            extractDataBytes { bytes =>
              val data = bytes.runFold(ByteString())(_ ++ _)
              onComplete(data) { t =>
                complete(t)
              }
            }
          }
        }

客户端上污染数范例:

 val numbers = Source.fromIterator(() =>
    Iterator.continually(Random.nextInt()))
    .map(n => ByteString(s"$n\n"))
  //make conform to withoutSizeLimit constrain
  val source = limitableByteSource(numbers)

  val bytes = HttpEntity(
    ContentTypes.`application/octet-stream`,
    // transform each number to a chunk of bytes
    source.take(10000)
  )
  val postRandom = HttpRequest(HttpMethods.POST,uri = s"http://localhost:8011/random")
  runService(postRandom,bytes)
    .andThen{case _ => sys.terminate()}

从点讨论我们询问了以Marshal,Unmarshal下层就是ByteString的操作与转换。下面是本次讨论示范源代码:

服务端:

import akka.actor._
import akka.stream._
import akka.stream.scaladsl._
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.model._
import akka.util.ByteString
import akka.http.scaladsl.model.HttpEntity._

import scala.util.Random

object ServerEntity extends App {

  implicit val httpSys = ActorSystem("httpSystem")
  implicit val httpMat = ActorMaterializer()
  implicit val httpEC = httpSys.dispatcher


  val numbers = Source.fromIterator(() =>
    Iterator.continually(Random.nextInt()))
    .map(n => ByteString(s"$n\n"))
  //make conform to withoutSizeLimit constrain
  val source = limitableByteSource(numbers)



  val route =
    path("random") {
      get {
        withoutSizeLimit {
          complete(
            HttpEntity(
              ContentTypes.`application/octet-stream`,
              // transform each number to a chunk of bytes
              source.take(1000))
          )
        }
      } ~
        post {
          withoutSizeLimit {
            extractDataBytes { bytes =>
              val data = bytes.runFold(ByteString())(_ ++ _)
              onComplete(data) { t =>
                complete(t)
              }
            }
          }
        }
    } ~ path("text") {
      get {
        complete("Hello World!")
      } ~
        post {
          withoutSizeLimit {
            extractDataBytes { bytes =>
              val data = bytes.runFold(ByteString())(_ ++ _)
              onComplete(data) { t =>
                complete(t)
              }
            }
          }
        }
    }


  val (port, host) = (8011,"localhost")

  val bindingFuture = Http().bindAndHandle(route,host,port)

  println(s"Server running at $host $port. Press any key to exit ...")

  scala.io.StdIn.readLine()

  bindingFuture.flatMap(_.unbind())
    .onComplete(_ => httpSys.terminate())

}

客户端:

import akka.actor._
import akka.stream._
import akka.stream.scaladsl._
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpEntity.limitableByteSource
import akka.http.scaladsl.model._

import scala.concurrent.duration._
import akka.util.ByteString

import scala.concurrent._
import scala.util._

object ClientEntity extends App {

  implicit val sys = ActorSystem("ClientSys")
  implicit val mat = ActorMaterializer()
  implicit val ec = sys.dispatcher

  def runService(request: HttpRequest, rentity: RequestEntity) = {
   val futResp = for {
     entity <- Future.successful(rentity)
     resp <- Http(sys).singleRequest(
       request.copy(entity = rentity)
     )
   } yield resp

   futResp
    .andThen {
      case Success(r@HttpResponse(StatusCodes.OK, _, entity, _)) =>
        val futEnt = entity.dataBytes.map(_.utf8String).runForeach(println)
             Await.result(futEnt, Duration.Inf) // throws if binding fails
             println("End of stream!!!")
      case Success(r@HttpResponse(code, _, _, _)) =>
        println(s"Download request failed, response code: $code")
        r.discardEntityBytes()
      case Success(_) => println("Unable to download rows!")
      case Failure(err) => println(s"Download failed: ${err.getMessage}")

    }
  }

  val reqText = HttpRequest(uri = s"http://localhost:8011/text")
//  runService(reqText,HttpEntity.Empty)
//    .andThen{case _ => sys.terminate()}

  val postText = HttpRequest(HttpMethods.POST,uri = s"http://localhost:8011/text")
  val uploadText = HttpEntity(
    ContentTypes.`text/plain(UTF-8)`,
    // transform each number to a chunk of bytes
    ByteString("hello world again")
  )
//  runService(postText,uploadText)
//    .andThen{case _ => sys.terminate()}

  val reqRandom = HttpRequest(uri = s"http://localhost:8011/random")
 //   runService(reqRandom,HttpEntity.Empty)
 //    .andThen{case _ => sys.terminate()}

  val numbers = Source.fromIterator(() =>
    Iterator.continually(Random.nextInt()))
    .map(n => ByteString(s"$n\n"))
  //make conform to withoutSizeLimit constrain
  val source = limitableByteSource(numbers)

  val bytes = HttpEntity(
    ContentTypes.`application/octet-stream`,
    // transform each number to a chunk of bytes
    source.take(10000)
  )
  val postRandom = HttpRequest(HttpMethods.POST,uri = s"http://localhost:8011/random")
  runService(postRandom,bytes)
    .andThen{case _ => sys.terminate()}


}