Akka 如果实体大小>;1K
使用Akka 2.4.7。我想记录整个Http响应。使用类似于关注代码的实现是从HttpEntity中提取数据的实现Akka 如果实体大小>;1K,akka,akka-stream,Akka,Akka Stream,使用Akka 2.4.7。我想记录整个Http响应。使用类似于关注代码的实现是从HttpEntity中提取数据的实现 def entityAsString(entity: HttpEntity) (implicit m: Materializer, ex: ExecutionContext): Future[String] = { entity.dataBytes.map(_.decodeString("UTF-8")).runWith(Sink.head) } 如果POST请求的有效
def entityAsString(entity: HttpEntity) (implicit m: Materializer, ex: ExecutionContext): Future[String] = {
entity.dataBytes.map(_.decodeString("UTF-8")).runWith(Sink.head)
}
如果POST请求的有效负载很小,那么这种方法效果很好。但从1K开始有一个例外:
java.lang.IllegalStateException: Substream Source cannot be materialized more than once
问题:为什么此异常取决于POST有效负载的大小。希望有任何可能的解决办法吗
完整日志消息:
2016-08-11 10:15:35,100 ERROR a.a.ActorSystemImpl [undefined]: Error during processing of request HttpRequest(HttpMethod(POST),http://localhost:3001/api/v2/exec,List(User-Agent: curl/7.30.0, Host: localhost:3001, Accept: */*, Expect: 100-continue, Timeout-Access: <function1>),HttpEntity.Default(multipart/form-data; boundary=-------------------------acebdf13572468; charset=UTF-8,5599,Source(SourceShape(StreamUtils$$anon$2.out), CompositeModule [2db5bfef]
Name: unnamed
Modules:
(unnamed) CompositeModule [4aac8b90]
Name: unnamed
Modules:
(SubSource%28EntitySource%29) GraphStage(EntitySource) [073d36ba]
(unnamed) [155dd7c9] copy of GraphStage(OneHundredContinueStage) [40b6c892]
(unnamed) [1b902132] copy of GraphStage(Collect) [75f65c1c]
(limitable) [76375468] copy of CompositeModule [59626a09]
Name: limitable
Modules:
(unnamed) GraphStage(unknown-operation) [1bee846d]
Downstreams:
Upstreams:
MatValue: Ignore
Downstreams:
SubSource.out -> GraphStage.in
GraphStage.out -> Collect.in
Collect.out -> unknown-operation.in
Upstreams:
GraphStage.in -> SubSource.out
Collect.in -> GraphStage.out
unknown-operation.in -> Collect.out
MatValue: Atomic(SubSource%28EntitySource%29[073d36ba])
(unnamed) [77d6c04c] copy of GraphStage(akka.http.impl.util.StreamUtils$$anon$2@30858cb0) [7e073049]
Downstreams:
SubSource.out -> GraphStage.in
GraphStage.out -> Collect.in
Collect.out -> unknown-operation.in
unknown-operation.out -> StreamUtils$$anon$2.in
Upstreams:
GraphStage.in -> SubSource.out
Collect.in -> GraphStage.out
unknown-operation.in -> Collect.out
StreamUtils$$anon$2.in -> unknown-operation.out
MatValue: Atomic(akka.stream.impl.StreamLayout$CompositeModule[4aac8b90]))),HttpProtocol(HTTP/1.1))
java.lang.IllegalStateException: Substream Source cannot be materialized more than once
at akka.stream.impl.fusing.SubSource$$anon$4.setCB(StreamOfStreams.scala:703)
at akka.stream.impl.fusing.SubSource$$anon$4.preStart(StreamOfStreams.scala:713)
at akka.stream.impl.fusing.GraphInterpreter.init(GraphInterpreter.scala:475)
at akka.stream.impl.fusing.GraphInterpreterShell.init(ActorGraphInterpreter.scala:380)
at akka.stream.impl.fusing.ActorGraphInterpreter.tryInit(ActorGraphInterpreter.scala:538)
at akka.stream.impl.fusing.ActorGraphInterpreter.preStart(ActorGraphInterpreter.scala:586)
at akka.actor.Actor$class.aroundPreStart(Actor.scala:489)
at akka.stream.impl.fusing.ActorGraphInterpreter.aroundPreStart(ActorGraphInterpreter.scala:529)
at akka.actor.ActorCell.create(ActorCell.scala:590)
at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:461)
at akka.actor.ActorCell.systemInvoke(ActorCell.scala:483)
at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:282)
at akka.dispatch.Mailbox.run(Mailbox.scala:223)
at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
2016-08-11 10:15:35100错误a.a.ActorSystemImpl[未定义]:处理请求HttpRequest(HttpMethod(POST)时出错,http://localhost:3001/api/v2/exec,列表(用户代理:curl/7.30.0,主机:localhost:3001,接受:*/*,期望:100继续,超时访问:),HttpEntity.Default(多部分/表单数据;边界=----------------------------acebdf13572468;字符集=UTF-85599,源(SourceShape(StreamUtils$$anon$2.out),CompositeModule[2db5bfef]
姓名:无名
模块:
(未命名)复合模块[4aac8b90]
姓名:无名
模块:
(子资源%28EntitySource%29)GraphStage(EntitySource)[073d36ba]
(未命名)[155dd7c9]GraphStage副本(100个连续阶段)[40b6c892]
(未命名)[1b902132]GraphStage副本(收集)[75f65c1c]
(可限制)[76375468]复合模块副本[59626a09]
名称:limitable
模块:
(未命名)GraphStage(未知操作)[1bee846d]
下游:
上游:
MatValue:忽略
下游:
子源输出->图形阶段输入
GraphStage.out->Collect.in
Collect.out->unknown-operation.in
上游:
图阶段输入->子源输出
Collect.in->GraphStage.out
未知-operation.in->Collect.out
MatValue:原子(子源%28EntitySource%29[073d36ba])
(未命名)[77d6c04c]GraphStage的副本(akka.http.impl.util.StreamUtils$$anon$2@30858cb0)[7e073049]
下游:
子源输出->图形阶段输入
GraphStage.out->Collect.in
Collect.out->unknown-operation.in
未知-operation.out->StreamUtils$$anon$2.in
上游:
图阶段输入->子源输出
Collect.in->GraphStage.out
未知-operation.in->Collect.out
StreamUtils$$anon$2.in->unknown-operation.out
MatValue:Atomic(akka.stream.impl.StreamLayout$CompositeModule[4aac8b90])、HttpProtocol(HTTP/1.1))
java.lang.IllegalStateException:子流源不能被物化多次
在akka.stream.impl.fusing.SubSource$$anon$4.setCB(StreamOfStreams.scala:703)
在akka.stream.impl.fusing.SubSource$$anon$4.preStart(StreamOfStreams.scala:713)
在akka.stream.impl.fusing.graphinterpeter.init(graphinterpeter.scala:475)
在akka.stream.impl.fusing.graphinterperterShell.init(ActorGraphExplorer.scala:380)
在akka.stream.impl.fusing.ActorGraphTranslator.tryInit(ActorGraphTranslator.scala:538)
在akka.stream.impl.fusing.ActorGraphTranslator.preStart(ActorGraphTranslator.scala:586)
在akka.actor.actor$class.aroundPreStart(actor.scala:489)
在akka.stream.impl.fusing.ActorGraphTranslator.aroundPreStart(ActorGraphTranslator.scala:529)
在akka.actor.ActorCell.create(ActorCell.scala:590)
在akka.actor.ActorCell.invokeAll$1(ActorCell.scala:461)
在akka.actor.ActorCell.systemInvoke(ActorCell.scala:483)
在akka.dispatch.Mailbox.processAllSystemMessages上(Mailbox.scala:282)
在akka.dispatch.Mailbox.run(Mailbox.scala:223)
在akka.dispatch.Mailbox.exec(Mailbox.scala:234)
位于scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
位于scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
位于scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
在scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)中
我假设实体。在调用此实体字符串之前,数据字节已经用于一些有用的目的,或者实体字符串
被调用两次。在一般情况下,HttpEntity
的内容不能重用。但是,HttpEntity.Strict
的内容可以重用。我假设entity.dataBytes
在调用这个entityAsString
之前已经被用于一些有用的目的,或者entityAsString
被调用了两次。在一般情况下,HttpEntity
的内容不能被重用。但是,HttpEntity.Strict
的内容可以被重用。我发现这些问题仍然与AKKAHTTP2.6.4,在查看了一些bug报告之后,这篇文章特别帮助我找到了解决方案
但是,在上面的引用中提到,它意味着<强>文件的内容被存储在内存中,而不是使用流。因此,我认为这是解决方案而不是解决方案。
还要注意的是,我没有发现fileUpload
和storeUploadedFile
之间的行为有任何不同。这两种方法都适用
解决方法:以下是我的函数示例
def createTestUploadWithStrict = toStrictEntity(3.seconds) {
(withoutSizeLimit &
post &
pathPrefix("test") &
fileUpload("data") &
formField("f1".as[MyCustomFormFiled])){
case ((metadata: FileInfo, fileStream: Source[ByteString, Any]), di:MyCustomFormFiled) => {
// Save the file
val file = tempDestination(metadata)
val sink = FileIO.toPath(file.toPath)
val writeResultFut = fileStream.runWith(FileIO.toPath(file.toPath))
val result = ???
// file is written to file
onComplete(writeResultFut) {
case Success(_) =>
complete(200 -> s"Working fine with data $result")
case Failure(e) =>
complete(500 -> s"Error while writing data file: $e")
}
}
}
}
并使用storeUploadedFile
:
def createTestUploadWithStrict = toStrictEntity(3.seconds) {
(withoutSizeLimit &
post &
pathPrefix("test2") &
storeUploadedFile("data", tempDestination) &
formField("device".as[MyCustomFormFiled])){
(metadata: FileInfo, file: File, di:MyCustomFormFiled) =>
val result = ???
complete(200 -> s"Working fine with data $result")
}
}
请注意,解组器隐式提供了:
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import spray.json._
trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol{
implicit val mycustomFormFieldFormat = jsonFormat2(MyCustomFormFiled) }
我发现这些问题仍然与Akka http 2.6.4相关,在查看了一些错误报告之后,这篇文章特别帮助我找到了解决方案
但是,在上面的引用中提到,它意味着<强>文件的内容被存储在内存中,而不是使用流。因此,我认为这是解决方案而不是解决方案。
还要注意的是,我没有发现fileUpload
和storeUploadedFile
之间的行为有任何不同。这两种方法都适用
解决方法:以下是我的函数示例
def createTestUploadWithStrict = toStrictEntity(3.seconds) {
(withoutSizeLimit &
post &
pathPrefix("test") &
fileUpload("data") &
formField("f1".as[MyCustomFormFiled])){
case ((metadata: FileInfo, fileStream: Source[ByteString, Any]), di:MyCustomFormFiled) => {
// Save the file
val file = tempDestination(metadata)
val sink = FileIO.toPath(file.toPath)
val writeResultFut = fileStream.runWith(FileIO.toPath(file.toPath))
val result = ???
// file is written to file
onComplete(writeResultFut) {
case Success(_) =>
complete(200 -> s"Working fine with data $result")
case Failure(e) =>
complete(500 -> s"Error while writing data file: $e")
}
}
}
}
并使用