将HTTP/REST请求转发到Spray中的另一个REST服务器

9
我有一些现有的REST服务(下面的#1和#2)在不同的端点上运行,只用于内部。现在我想使用Spray将其中一些REST API(API-1和API-2)外部公开,因为该外部端点还将提供一些其他API(API-3,API-4)。
有没有一种简单/推荐的方法将外部REST请求转发到现有REST端点的新端点?

2
我不完全理解问题的意思,但如果你只想要简单的转发,为什么不在前面放置Apache或一些Web服务器,并让它通过proxypass来实现呢?反向代理/负载均衡器可能比spray服务器更好地路由流量。 - Bruce Lowe
如果我只需要路由,那么我本来可以做到这一点。然而,我需要在新的REST服务中提供一些额外的API(API-3、API-4),并且包装对现有API(API-1、API-2)的调用。 - Soumya Simanta
1
你仍然可以使用类似nginx / apache的东西来支持你的场景,而无需在scala代码中进行代理。 你可以在web服务器配置中设置规则,仅支持代理某些url(API 1和2),然后让其余部分(3和4)通过到底层的spray服务器。我们在nginx中确实做到了这一点。 - cmbaxter
@cmbaxter - 这很有帮助。如果可能的话,你能指点我一些开始配置nginx的地方吗? - Soumya Simanta
1
这里是 proxy_pass 指令的文档。应该作为一个起点。http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass - cmbaxter
显示剩余4条评论
2个回答

4

听起来你想要的是建议中的proxyTo指令:

path("foo") {
  get {
    proxyTo("http://oldapi.example.com")
  }
}

或者更可能的是proxyToUnmatchedPath。这方面已经有一个问题被提出:

https://github.com/spray/spray/issues/145

看起来有人正在这方面努力;这是Spray分支中的提交记录:

https://github.com/bthuillier/spray/commit/d31fc1b5e1415e1b908fe7d1f01f364a727e2593

但是这个提交似乎还没有被合并到Spray主仓库中。您可以在问题页面上了解其状态。
此外,这里有一篇来自CakeSolutions的博客文章,介绍如何手动进行代理。

http://www.cakesolutions.net/teamblogs/http-proxy-with-spray

该页面的评论指出,Spray有一个名为ProxySettings的未记录功能,并指向以下测试:

https://github.com/spray/spray/blob/master/spray-can-tests/src/test/scala/spray/can/client/ProxySpec.scala

更新:Soumya已在spray-user Google Group上向Spray团队提出了这个问题:

https://groups.google.com/forum/#!topic/spray-user/MlUn-y4X8RE


3
我能够通过CakeSolution博客的帮助来代理一个服务。在下面的例子中,代理运行在http://localhost:20000上,实际的REST端点运行在http://localhost:7001上。

不确定如何使用这种方法代理多个服务。

我喜欢@cmbaxter将Nginx用作代理的解决方案,但我仍然很好奇是否有一种方式可以扩展以下方法来在Spray中实现它。

import akka.actor.{ActorRef, Props}
import akka.io.IO
import akka.util.Timeout
import spray.can.Http
import spray.can.Http.ClientConnectionType
import spray.http.HttpResponse
import spray.routing.{RequestContext, HttpServiceActor, Route}


import scala.concurrent.duration._
import akka.pattern.ask


object ProxyRESTService {

   def main(args: Array[String]) {

   //create an actor system
   implicit val actorSystem = akka.actor.ActorSystem("proxy-actor-system")
   implicit val timeout: Timeout = Timeout(5 seconds)
   implicit val dis = actorSystem.dispatcher

   //host on which proxy is running
   val proxyHost = "localhost"
   //port on which proxy is listening
   val proxyPort = 20000

  //host where REST service is running
  val restServiceHost = "localhost"
  //port where REST service is running
  val restServicePort = 7001

  val setup = Http.HostConnectorSetup(
   proxyHost,
   proxyPort,
   connectionType = ClientConnectionType.Proxied(restServiceHost,   restServicePort)
)

IO(Http)(actorSystem).ask(setup).map {
  case Http.HostConnectorInfo(connector, _) =>
    val service = actorSystem.actorOf(Props(new ProxyService(connector)))
    IO(Http) ! Http.Bind(service, proxyHost, port = proxyPort)
}
}

}

.

class ProxyService(connector: ActorRef) extends HttpServiceActor  {
  implicit val timeout: Timeout = Timeout(5 seconds)
  implicit def executionContext = actorRefFactory.dispatcher
  val route: Route = (ctx: RequestContext) => ctx.complete(connector.ask(ctx.request).mapTo[HttpResponse])
  def receive: Receive = runRoute(route)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接