[翻译]squbs官网之5 实现HTTP(s)服务

概述

HTTP是最普遍的集成协议。它是 web 服务的基础,包括客户端和服务器端)。Akka HTTP 提供了强大的服务器和客户端 API。squbs 有意图保持这些 api 不改变。相反,squbs提供基础结构来允许生产就绪的使用这些API,通过提供HTTP监听器(服务可以使用它来接收和处理请求)、管道(在请求到达应用之前以及在响应离开应用上线之前,允许日志、监视、身份验证/授权)的标准配置。

squbs支持Akka HTTP用于定义服务的低级别和高级别服务端API。两个API都打到了全生产化的支持,例如监听器、管道、日志和监控。另外,squbs支持Scala和Java风格的服务定义。这些服务处理器在类中声明,并通过META-INF/squbs-meta.conf(通过此文件中的 squbs 服务项)注册到squbs。每个服务样式都以相同的方式注册, 只需提供类名和配置。

所有的squbs服务定义都可以访问字段上下文(它是一种akka.actor.ActorContext,对于访问actor系统,scheduler和各种Akka设施。

依赖

启动服务器和注册服务定义需要下面的依赖:

"org.squbs" %% "squbs-unicomplex" % squbsVersion

定义服务

可以使用高级别或低级别 API 在 Scala 或 Java 中定义服务。服务定义类必须具有无参构造函数, 并且必须注册才能处理传入的 Http 请求。

高级别Scala API
高级别服务端API由Akka HTTP的路由工件和它的指令表示。为了使用路由来处理请求,仅提供一个继承org.squbs.unicomplex.RouteDefinition特质的类,并像如下提供路由函数:·

import akka.http.scaladsl.server.Route
import org.squbs.unicomplex.RouteDefinition

class PingPongSvc extends RouteDefinition {

  def route: Route = path("ping") {
    get {
      complete("pong")
    }
  }

  // Overriding the rejectionHandler is optional
  override def rejectionHandler: Option[RejectionHandler] =
    Some(RejectionHandler.newBuilder().handle {
      case ServiceRejection => complete("rejected")
    }.result())

  // Overriding the exceptionHandler is optional
  override def exceptionHandler: Option[ExceptionHandler] =
    Some(ExceptionHandler {
      case _: ServiceException => complete("exception")
    })

除了定义路由外, 还可以通过相应地重写 RejectionHandlerExceptionHandler 函数来提供 RejectionHandlerExceptionHandler。这些可以在上面的例子中看到。

可以参考Akka HTTP的详细文档。

低级别Scala API
使用Scala低级别API,仅需继承org.squbs.unicomplex.FlowDefinition并覆盖flow方法。flow方法需要返回Flow[HttpRequest, HttpResponse, NotUsed],使用了Akka HTTP提供的Scala DSL和模型,如下所示:

import akka.http.scaladsl.model.Uri.Path
import akka.http.scaladsl.model._
import akka.stream.scaladsl.Flow
import org.squbs.unicomplex.FlowDefinition

class SampleFlowSvc extends FlowDefinition {

  def flow = Flow[HttpRequest].map {
    case HttpRequest(_, Uri(_, _, Path("ping"), _, _), _, _, _) =>
      HttpResponse(StatusCodes.OK, entity = "pong")
    case _ =>
      HttpResponse(StatusCodes.NotFound, entity = "Path not found!")
}

可以参考Akka HTTP的详细文档。

服务注册

服务的元数据在META-INF/squbs-meta.conf中申明,如下所示:

cube-name = org.sample.sampleflowsvc
cube-version = "0.0.2"
squbs-services = [
  {
    class-name = org.sample.SampleFlowSvc
    web-context = sample # You can also specify bottles/v1, for instance.

    # The listeners entry is optional, and defaults to 'default-listener'.
    listeners = [ default-listener, my-listener ]

    # Optional, defaults to a default pipeline.
    pipeline = some-pipeline

    # Optional, disables the default pipeline if set to false.  If missing, it is set to on.
    defaultPipeline = on

    # Optional, only applies to actors.
    init-required = false
  }
]

class-name参数标识了服务定义类(可以使用Java或者Scala实现,可以使用低级别或高级别API)。

web-context是一个字符串,唯一标识了要派发给此服务的请求的 web 上下文。请参考"web上下文"部分的详细内容。

listeners参数是可选的,会声明一个侦听程序列表以绑定此服务。侦听器绑定在下面的 "侦听器绑定" 部分中讨论。

管道是一组前处理器和后处理器(在请求处理器处理请求之前和之后)。管道的名称可以由pipeline参数指定。随着管道被指定,一个默认的对于请求/响应的管道设置将一起插入。为了关闭此服务的默认管道,你可以在META-INF/squbs-meta.conf中设置defaultPipeline = off。可在“请求/响应管道”看到更多信息。

监听器绑定
与直接编程Akka HTTP 不同, squbs 通过其侦听器提供所有套接字绑定和连接管理。只需通过上面讨论的一个或多个API提供请求/响应处理, 并将这些实现注册到 squbs。这使得跨服务的绑定配置标准化, 并允许跨服务的统一配置管理。

监听器通常在application.conf或者reference.conf中申明,并放在项目的src/main/resources目录下。监听器申明了接口、端口、Https安全属性、和名称别名,并在配置中解释。

服务处理器将自身附加到一个或多个侦听器。listeners属性是处理器应绑定到的侦听器或别名的列表。如果未定义侦听器, 它将默认为default-listener

通配符“*”(注意,它必须被引用否则无法正确解释)是一个特殊情况,它意味着将此处理器附加到所有激活的监听器器上。但是,如果它尚未被一个具体的附加的处理器激活,它本身不会激活任何监听器。如果某处理器需激活默认侦听器,并附加到由其他处理器激活的其他侦听器, 则这样的附加需要分别指定, 如下所示:

listeners = [ default-listener, "*" ]

web 上下文

每个服务入口点都绑定到唯一的 web 上下文, 它是由/字符分隔的主要路径段。例如,url http://mysite.com/my-context/index 匹配上下文 "my-context",如果已注册。它也可以匹配根上下文,如果 "my-context"没有注册。Web 上下文不一定是路径的第一个斜线分隔的段。依赖于上下文注册, 它可能匹配多个这样的段。一个具体的例子是一个带有服务版本的 URL。 URL http://mysite.com/my-context/v2/index 即可以以my-context ,也可以以my-context/v2 作为web上下文,依赖于上下文注册的什么。如果my-context 和 my-context/v2 都注册了,按照最长的将匹配——在本例中my-context/v2将用于路由请求。这对于将不同版本的 web 接口或 API 分离到不同的cube/模块中非常有用。

已注册的 web 上下文不能以/字符开头。在多段上下文的情况下, 它可以用/字符作为段分隔符。并且 "" 作为根上下文。如果多个服务与请求匹配, 则最长的上下文匹配优先。

虽然 web 上下文是在元数据中注册的, 但路由, 特别是在低级别 API 中定义的流需要知道它所服务的 web 上下文。

Scala 服务处理器类将混合org.squbs.unicomplex.WebContext特质中。这样做会将以下字段添加到您的类中:

scala
   val webContext: String

在构建对象时, webContext 字段被初始化为在元数据中设置的已注册 web 上下文的值, 如下所示:

class SampleFlowSvc extends FlowDefinition with WebContext {

  def flow = Flow[HttpRequest].map {
    case HttpRequest(_, Uri(_, _, Path(s"$webContext/ping"), _, _), _, _, _) =>
      HttpResponse(StatusCodes.OK, entity = "pong")
    case _ =>
      HttpResponse(StatusCodes.NotFound, entity = "Path not found!")
  }
}

高级别路由 API 的规则和行为

1.并发状态访问:提供的路由可由多个连接使用,因此可用并发线程。如果路由访问封装在RouteDefinition ()类中的 状态,需要注意的是这样的访问时并发的,读写都是。这种访问(读取或写入封装类中可变状态)是不安全的。在这种情况下, 强烈推荐使用Akka Actor或Agent 。
2.访问actor上下文:默认情况下, RouteDefinition 可以使用context字段访问 ActorContext。这可以用于创建新的actor或访问其他actor。
3.访问web上下文:对于RouteDefinition,如果已混入WebContext特质,将可以访问webContext字段。此字段用于确定来自此RouteDefinition处理请求的根目录下的 web 上下文或路径。

低级别流 API 的规则和行为

在实现 FlowDefinition () 时, 您必须牢记一些规则:
1.恰好一个响应: 应用程序的责任是为每个请求生成一个响应。
2.响应顺序:响应的顺序与相关联的请求的顺序相匹配(如果启用了HTTP流水线,则在多个传入请求的处理可能重叠的情况下,是相关的)。
3.并发状态的访问:流可以多次物化,产生多个Flow的示例。如果这些实例访问封装在FlowDefinition 里的状态,需要注意的是这样的访问是并发的,包括读和写。这样的访问(读或写封装类中的可变状态)是不安全的。这种情况,强烈建议使用Akka Actor或者Agent。
4.访问actor上下文:默认情况下, FlowDefinition 可以使用context字段访问 ActorContext。这可以用于创建新的actor或访问其他actor。
5.访问web上下文:对于FlowDefinition,如果已混入WebContext特质,将可以访问webContext字段。此字段用于确定来自此 FlowDefinition处理请求的根目录下的 web 上下文或路径。
6.请求路径:HttpRequest对象未被修改地交给这个流。webContext在请求的路径中。处理带有已知的webContext的请求,这是用户的工作 (如上所见) 。换言之, 低级别 API 直接处理 HttpRequest, 需要手动将 web 上下文考虑到路径匹配。

指标

squbs带有用于指标收集的构建前管道元素,并且squbs activator模板设置它们的默认值。因此, 每个 squbs http (s) 服务都可以在没有任何代码更改或配置的情况下, 收集现成的Codahale Metrics。请注意, squbs指标集合不需要 AspectJ 或任何其他运行时代码的编写。默认情况下, 在 JMX 上可以使用以下指标标准:

  • 请求计时器
  • 请求计数器
  • 每个http响应码的计量器:2xx, 3xx, 4xx, 5xx
  • 服务返回的每个异常类型的计量器

你可以通过MetricsExtension(system).metrics访问MetricRegistry。这使您可以创建更多的计量器, 计时器, 直方图等, 或传递给不同类型的指标报表。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容