[Play Framework]Body parsers——请求主体解析器
来源:互联网 发布:手机淘宝关注是收藏吗 编辑:程序博客网 时间:2024/05/01 23:06
什么是请求主体解析器
通常HTTP的PUT和POST请求都包含一个主体(body)。该主体可以是任意格式的,并且通过‘Content-Type‘定义其具体格式。在Play中,请求主体解析器将这些请求的主题内容转换为对应的Scala可以直接读取/操作的值。
虽然,HTTP请求的主体可以是非常庞大的,并且请求主体解析器通常也不能一直等待并将其载入到系统内存中。BodyParser[A]实际上是基于Iteratee[Array[Byte],A]的,这就意味着可以获取大量字节码并计算其对应的A类型的Scala值。
考虑以下几个例子:
- 文本的请求主体解析器可以将字节码转换成为String,并且将该值作为Iteratee[Array[Byte],A]结果返回;
- 文件的请求主体解析器可以存储文本的各个部分至本地,并且返回一个作为Iteratee[Array[Byte],File]结果的java.io.File类型的文本引用;
- 一个S3的请求主体解析器可以将请求主体的内容推送至Amazon S3服务器,并且返回一个作为Iteratee[Array[Byte],S3ObjectId]结果的S3服务器Id对象。
作为请求主体解析器的附加功能,它也可以用来在解析请求实体之前访问HTTP请求头,并且适时的进行一些预检查。例如:实体解析器能够检查某些HTTP头并进行适当的集合操作。
其实请求主体解析器并不是真正意义上的Iteratee[Array[Byte],A],而是Iteratee[Array[Byte],Either[Result,A]],因此,请求主体解析器在它无法正确的计算出正确的请求值时,它具有直接传递HTTP请求结果的职责(例如,返回400 BAD_REQUEST,412 PRECONDITION_FAILED或者413 REQUEST_ENTITY_TOO_LARGE)。
一旦请求主体解析器完成了它的工作并且返回了对应A类型的值,对应的Action方法就根据解析出的HTTP请求中的值计算出相应的结果。
更多Action的内容
在之前提到Action是一个Request=>Result的方法。这样说其实并不完全正确。我们来仔细审视以下Action trait:
trait Action[A] extends (Request[A] => Result) { def parser: BodyParser[A]}
A为泛化类型,Action特质中必须定义一个BodyParser[A]。对于Request[A]是这样定义的:
trait Request[+A] extends RequestHeader { def body: A}
A为请求主体的类型。请求主体的类型可以是任意的Scala类型,例如:String,NodeSeq,Array[Byte],JsonValue或者java.io.Fil,只要是请求主体解析器能够处理的类型都可以。
综上所述,Action[A]使用了BodyParser[A]来从HTTP请求中获取类型A的值,并且构建一个Request[A]对象有Action方法进行处理。
定义请求实体解析器 parser: AnyContent
在以上的例子中,没有特例化请求实体解析器。那么默认情况下它是如何工作的?默认情况下Play会获取一个play.api.mvc.AnyContent的实例。
该请求主体解析器会检查Content-Type请求头并且确定所处理的请求主体的类型:
- Text/plain——String
- Application/json——JsValue
- application/xml, text/xml or application/XXX+xml——NodeSeq
- application/form-url-encoded——Map[String, Seq[String]]
- multipart/form-data——MultipartFormData[TemporaryFile]
- any other content typ——RawBuffer
例如:
def save = Action { request => val body: AnyContent = request.body val textBody: Option[String] = body.asText // Expecting text body textBody.map { text => Ok("Got: " + text) }.getOrElse { BadRequest("Expecting text/plain request body") }}
特别指定请求主体解析器
Play定义的请求主体解析器在play.api.mvc.BodyParsers.parse中。例如,定义某个Action来处理某个文本主体:
def save = Action(parse.text) { request => Ok("Got: " + request.body)}
这段代码看似简单。其实一旦出现了某些错误,通常会得到一个400 BAD_REQUEST。我们没有必要在Action里定义检查的代码,我们可以假定request.body包含了String的内容实体。
我们也可以通过以下方式处理:
def save = Action(parse.tolerantText) { request => Ok("Got: " + request.body)}
以上代码不会检测Content-Type中的内容,并直接使用Request的主体内容为String类型。
> tolerant就是提供对应各种实体解析方式的方法
以下是用于文件存储的实例:
def save = Action(parse.file(to = new File("/tmp/upload"))) { request => Ok("Saved the request content to " + request.body)}
请求主体解析器的组合使用
在上述例子中,所有的请求主体都存放在同一个文件中。该问题的处理需要我们编辑一个自定义的主体解析器,该解析器可以从请求的Session中抽取出用户名或其他的一些信息。
val storeInUserFile = parse.using { request => request.session.get("username").map { user => file(to = new File("/tmp/" + user + ".upload")) }.getOrElse { sys.error("You don't have the right to upload here") }}def save = Action(storeInUserFile) { request => Ok("Saved the request content to " + request.body)}
此处我们并没有编写特定的主体解析器,仅仅是结合了已有的解析器,让它们协同完成工作。通常情况下,这种做法是足以应付绝大多数的用例的。
实体内容长度限制
基于文本的请求主体解析器(例如 text,json,xml或者formUrlEncoded)通常会对文本长度有最长长度的限定,这样做的目的在于使得该内容可以全部载入到内存中。
文本内容的最大长度在Play中默认为100KB,这个值用户可以通过以下方式修改:
// Accept only 10KB of data.def save = Action(parse.text(maxLength = 1024 * 10)) { request => Ok("Got: " + text)}
- [Play Framework]Body parsers——请求主体解析器
- Play framework Body分析器
- play framework2学习之旅<2.5>Body parsers
- Play Framework 的请求处理流程
- Play framework 浅谈 之请求处理流程
- 1.5.8 THE RAW REQUEST BODY(请求的主体部分)
- Solr所有的查询解析器Query Parsers
- [Play Framework]Manipulating Results——操作结果
- [Play Framework]Session and Flash scopes——用Play操作Session和Flash数据
- play framework
- play framework
- play framework
- Play Framework
- play framework
- play framework
- play Framework play json
- Play framework基本概念、请求处理流程、开发生命周期
- AngularJs-$parsers自我理解-解析
- Android中的简单图像处理
- ZOJ 3879 — Capture the Flag
- git学习(分支管理)
- Subsets II -- leetcode
- Sicily 14181. Flying Safely
- [Play Framework]Body parsers——请求主体解析器
- 02-线性结构2. 一元多项式求导 (25)
- Java垃圾回收机制
- 疯狂Java之学习笔记(15)-------------内部类
- vb.net—配置文件
- Javascript中的构造函数与原型
- Android Studio简单设置
- jquery中attr和prop的区别
- php面试题常见知识点总结