概述
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")
})
除了定义路由外, 还可以通过相应地重写 RejectionHandler 和 ExceptionHandler 函数来提供 RejectionHandler和ExceptionHandler。这些可以在上面的例子中看到。
可以参考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。这使您可以创建更多的计量器, 计时器, 直方图等, 或传递给不同类型的指标报表。