加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 为什么调用错误或在BodyParser的Iteratee中完成请求在P

发布时间:2020-12-16 09:26:01 所属栏目:安全 来源:网络整理
导读:我试图了解Play 2.0框架的反应I / O概念.为了从一开始就更好地理解,我决定跳过框架的助手来构造不同种类的迭代,并从头开始编写一个自定义Iteratee,供BodyParser用来解析请求体. 从Iteratees和ScalaBodyParser文档中提供的信息开始,以及关于播放被动I / O的两
我试图了解Play 2.0框架的反应I / O概念.为了从一开始就更好地理解,我决定跳过框架的助手来构造不同种类的迭代,并从头开始编写一个自定义Iteratee,供BodyParser用来解析请求体.

从Iteratees和ScalaBodyParser文档中提供的信息开始,以及关于播放被动I / O的两个演示文稿,这是我想出的:

import play.api.mvc._
import play.api.mvc.Results._
import play.api.libs.iteratee.{Iteratee,Input}
import play.api.libs.concurrent.Promise
import play.api.libs.iteratee.Input.{El,EOF,Empty}

01 object Upload extends Controller {
02   def send = Action(BodyParser(rh => new SomeIteratee)) { request =>
03     Ok("Done")
04   }
05 }
06
07 case class SomeIteratee(state: Symbol = 'Cont,input: Input[Array[Byte]] = Empty,received: Int = 0) extends Iteratee[Array[Byte],Either[Result,Int]] {
08   println(state + " " + input + " " + received)
09
10   def fold[B](
11     done: (Either[Result,Int],Input[Array[Byte]]) => Promise[B],12     cont: (Input[Array[Byte]] => Iteratee[Array[Byte],Int]]) => Promise[B],13     error: (String,Input[Array[Byte]]) => Promise[B]
14   ): Promise[B] = state match {
15     case 'Done => { println("Done"); done(Right(received),Input.Empty) }
16     case 'Cont => cont(in => in match {
17       case in: El[Array[Byte]] => copy(input = in,received = received + in.e.length)
18       case Empty => copy(input = in)
19       case EOF => copy(state = 'Done,input = in)
20       case _ => copy(state = 'Error,input = in)
21     })
22     case _ => { println("Error"); error("Some error.",input) }
23   }
24 }

(备注:所有这些对我来说都是新的,所以请原谅,如果有关于此的话就是全部废话.)
Iteratee非常愚蠢,它只读取所有块,总结接收的字节数并打印出一些消息.当我用一些数据调用控制器动作时,一切都按预期工作 – 我可以观察到Iteratee接收到所有数据块,当读取所有数据时,它切换到状态完成并且请求结束.

现在我开始使用代码了,因为我想看看这两种情况的行为:

>在读取所有输入之前切换到状态错误.
>在读取所有输入之前切换到完成状态并返回Result而不是Int.

我对上述文档的理解是两者都应该是可能的,但实际上我无法理解观察到的行为.为了测试第一种情况,我将上面代码的第17行更改为:

17       case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Error else 'Cont,input = in,received = received + in.e.length)

所以我只是添加了一个条件,如果收到超过10000个字节,就会切换到错误状态.我得到的输出是这样的:

'Cont Empty 0
'Cont El([B@38ecece6) 8192
'Error El([B@4ab50d3c) 16384
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error

然后请求永远挂起,永远不会结束.我对上述文档的期望是,当我在Iteratee的fold中调用error函数时,应该停止处理.这里发生的事情是,在调用错误后多次调用Iteratee的fold方法 – 然后请求挂起.

当我在读取所有输入之前切换到完成状态时,行为非常相似.将第15行更改为:

15    case 'Done => { println("Done with " + input); done(if (input == EOF) Right(received) else Left(BadRequest),Input.Empty) }

和第17行:

17       case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Done else 'Cont,received = received + in.e.length)

产生以下输出:

'Cont Empty 0
'Cont El([B@16ce00a8) 8192
'Done El([B@2e8d214a) 16384
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)

请求再次挂起.

我的主要问题是为什么请求悬在上述案例中.如果有人能够阐明这一点我会非常感激!

解决方法

你的理解是完全正确的,我只是推动修复掌握:

https://github.com/playframework/Play20/commit/ef70e641d9114ff8225332bf18b4dd995bd39bcc

修复了Iteratees中的两种情况和例外情况.

在案例类中很好地使用副本来执行Iteratee BTW.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读