Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 我的http请求在Akka future中变为空_Scala_Akka_Scalatra - Fatal编程技术网

Scala 我的http请求在Akka future中变为空

Scala 我的http请求在Akka future中变为空,scala,akka,scalatra,Scala,Akka,Scalatra,我的服务器应用程序使用Scalatra、json4s和Akka 它收到的大多数请求都是POST,它们会立即返回到客户端,并给出固定的响应。实际响应以异步方式发送到客户端的服务器套接字。为此,我需要从http请求中getRemoteAddr。我正在使用以下代码进行尝试: case class MyJsonParams(foo:String, bar:Int) class MyServices extends ScalatraServlet { implicit val formats = D

我的服务器应用程序使用Scalatra、json4s和Akka

它收到的大多数请求都是POST,它们会立即返回到客户端,并给出固定的响应。实际响应以异步方式发送到客户端的服务器套接字。为此,我需要从http请求中
getRemoteAddr
。我正在使用以下代码进行尝试:

case class MyJsonParams(foo:String, bar:Int)

class MyServices extends ScalatraServlet {
  implicit val formats = DefaultFormats

  post("/test") {
    withJsonFuture[MyJsonParams]{ params =>
      // code that calls request.getRemoteAddr goes here
      // sometimes request is null and I get an exception
      println(request)
    }
  }

  def withJsonFuture[A](closure: A => Unit)(implicit mf: Manifest[A]) = {
    contentType = "text/json"
    val params:A = parse(request.body).extract[A]
    future{
      closure(params)
    }      
    Ok("""{"result":"OK"}""")
  }    
}
withJsonFuture
函数的目的是将一些样板文件移出路由处理

这有时有效(为
request
打印一个非空值),有时
request
为空,这让我感到非常困惑。我怀疑我将来一定会“关闭”
请求。但是,当没有其他请求进行时,受控测试场景也会发生错误。我会想象,
请求
是不可变的(也许我错了?)

为了解决此问题,我将代码更改为:

case class MyJsonParams(foo:String, bar:Int)

class MyServices extends ScalatraServlet {
  implicit val formats = DefaultFormats

  post("/test") {
    withJsonFuture[MyJsonParams]{ (addr, params) =>
      println(addr)
    }
  }

  def withJsonFuture[A](closure: (String, A) => Unit)(implicit mf: Manifest[A]) = {
    contentType = "text/json"
    val addr = request.getRemoteAddr()
    val params:A = parse(request.body).extract[A]
    future{
      closure(addr, params)
    }      
    Ok("""{"result":"OK"}""")
  }    
}

这似乎奏效了。但是,我真的不知道它是否还包括任何与并发相关的糟糕编程实践,这些实践可能会在将来导致错误(“未来”在其最常见的意义上是指未来:)。

我不知道scalatra,但乍一看,
withJsonFuture
函数返回一个
OK
,但也通过
future{closure(addr,params)}
调用创建一个线程

如果后一个线程在处理
OK
后运行,则响应已发送,请求已关闭/GCed

为什么要创建一个
Future
来运行您的
closure


如果
withJsonFuture
需要返回
Future
(再次抱歉,我不知道scalatra),您应该将该函数的整个主体包装在
Future

中,我不知道scalatra,但是您正在访问一个名为
request
的值,而您没有定义自己,这是可疑的。我猜它是扩展
ScalatraServlet
的一部分。如果是这种情况,那么可能是可变状态,即在请求开始时(由Scalatra)设置,然后在请求结束时取消。如果发生了这种情况,那么您的解决方法就可以了,就像在
未来
块之前将
请求
分配给另一个val,比如
val myRequest=request
,然后在未来和闭包中作为
myRequest
访问它一样。

我会尽力解释的

在您的示例中,
post(“/test”)
中的代码是一个匿名函数。请注意,它不接受任何参数,甚至不接受当前请求对象。 相反,scalatra将在调用您自己的处理程序之前将当前请求对象存储在线程本地值中,然后您可以通过
ScalatraServlet.request
将其取回

这是经典的动态范围模式。它的优点是,您可以编写许多实用程序方法来访问当前请求并从处理程序调用它们,而无需显式地传递请求

现在,当您使用异步代码时,问题就来了。 在您的例子中,withJsonFuture中的
代码在处理程序最初调用的原始线程之外的另一个线程上执行(它将在
ExecutionContext
的线程池中的线程上执行)。 因此,当访问线程局部变量时,您访问的是线程局部变量的一个完全不同的实例。 简单地说,经典的动态范围模式不适合异步上下文

这里的解决方案是在处理程序的最开始捕获请求,然后专门引用:

post("/test") {
  val currentRequest = request
  withJsonFuture[MyJsonParams]{ params =>
    // code that calls request.getRemoteAddr goes here
    // sometimes request is null and I get an exception
    println(currentRequest)
  }
}

坦率地说,这很容易出错,所以如果您处于同步上下文中,我个人会避免使用Scalatra。

尝试在您的类声明中添加带有FutureSupport的


类MyServices使用FutureSupport{}扩展ScalatrServlet

我想这也可能与尝试做一些与框架建议不同的事情有关。它们有自己的json和futures组件,但文档记录有点不足。我想这是Scala web框架的一个普遍问题。然而,尽管有点肤浅,我还是要说Scalatra的文档是本课程中最完整、对初学者最友好的文档之一。也许电梯有更好的文件,但它太重了,我的需要。我急切地等待着Scalatra MEAP的书,但到目前为止,我没有看到在编写章节方面有太多进展。他们确实有一个
AsyncResult
类,但这并不能解决使用本地线程的问题。遗憾的是,您仍然必须在处理程序开始之前捕获请求。我的直觉告诉我,scalatra添加了异步支持,这当然是正确的,这也是scalatra 2.2拥有非常方便的
AsyncResult
类的原因。@RandallSchulz:我不使用
AsyncResult
,因为我想立即发送响应。真正的响应以异步方式发送到客户端的服务器套接字(它不是浏览器,而是Adobe Air应用程序)。未来发生的事情是火和遗忘。我使用的是未来,而不是参与者,因为参与者序列化请求,我希望它们并行运行。我知道我可以培养出一个短命的演员,但未来似乎不那么冗长。