一个http请求是一个请求头后面跟着一个请求体,头部信息比较短,可以安全的缓存在内存中,在Play中头部信息使用RequestHeader类进行建模。请求体的内容可能较大,使用流stream的形式进行建模。

然而,有许多请求体是比较小的,因此Play提供了一个BodyParser抽象用于将流中的信息转换为内存对象。由于Play是一个异步框架,对流的处理不使用传统的InputStream,因为该方法在读取时会阻塞

整个线程直到数据读取完毕。Play中使用异步的Akka Stream进行处理,Akka Stream是Reactive Streams的一个实现。

一、使用play内部的解析器

1.在不指定解析器的情况下,play会使用内部的解析器根据请求头的Content-Type字段来判断解析后的类型,application/json会被解析为JsValue,application/x-www-form-urlencoded会被解析为Map[String, Seq[String]]

def save = Action { request: Request[AnyContent] =>
val body: AnyContent = request.body
val jsonBody: Option[JsValue] = body.asJson // Expecting json body
jsonBody.map { json =>
Ok("Got: " + (json \ "name").as[String])
}.getOrElse {
BadRequest("Expecting application/json request body")
}
}
  • text/plainString, accessible via asText.
  • application/jsonJsValue, accessible via asJson.
  • application/xmltext/xml or application/XXX+xmlscala.xml.NodeSeq, accessible via asXml.
  • application/x-www-form-urlencodedMap[String, Seq[String]], accessible via asFormUrlEncoded.
  • multipart/form-dataMultipartFormData, accessible via asMultipartFormData.
  • Any other content type: RawBuffer, accessible via asRaw.

2.指定解析器类型

def save = Action(parse.json) { request: Request[JsValue]  =>Ok("Got: " + (request.body \ "name").as[String])}

忽略content-type,尽力把请求体解析为json 类型

def save = Action(parse.tolerantJson) { request: Request[JsValue]  =>Ok("Got: " + (request.body \ "name").as[String])}

将请求体存为一个文件

def save = Action(parse.file(to = new File("/tmp/upload"))) { request: Request[File]  =>
Ok("Saved the request content to " + request.body)
}

之前是所有用户都存在一个文件里,现在每个用户都存一个文件

val storeInUserFile = parse.using { request =>
request.session.get("username").map { user =>
parse.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)
}

默认内存中最大缓存为100KB,但是可以通过application.conf进行设置: play.http.parser.maxMemoryBuffer=128K

而磁盘最大缓存默认为10MB, play.http.parser.maxDiskBuffer

也可以在函数中设置:

// 设置最大为10KB数据
def save = Action(parse.text(maxLength = 1024 * 10)) { request: Request[String] =>
Ok("Got: " + text)
}
def save = Action(parse.maxLength(1024 * 10, storeInUserFile)) { request =>
Ok("Saved the request content to " + request.body)
}

二、自定义一个解析器

1.当你不想解析时,可以把请求体转到别的地方

import javax.inject._
import play.api.mvc._
import play.api.libs.streams._
import play.api.libs.ws._
import scala.concurrent.ExecutionContext
import akka.util.ByteString class MyController @Inject() (ws: WSClient, val controllerComponents: ControllerComponents)
(implicit ec: ExecutionContext) extends BaseController { def forward(request: WSRequest): BodyParser[WSResponse] = BodyParser { req =>
Accumulator.source[ByteString].mapFuture { source =>
request
.withBody(source)
.execute()
.map(Right.apply)
}
} def myAction = Action(forward(ws.url("https://example.com"))) { req =>
Ok("Uploaded")
}
} 

2.通过akka Streams定制解析器

对akka Stream的讨论超出本文的内容,最好去参考akka的相关文档,https://doc.akka.io/docs/akka/2.5/stream/index.html?language=scala

以下例子是一个CSV文件的解析器,该实例基于 
https://doc.akka.io/docs/akka/2.5/stream/stream-cookbook.html?language=scala#parsing-lines-from-a-stream-of-bytestrings

import play.api.mvc.BodyParser
import play.api.libs.streams._
import akka.util.ByteString
import akka.stream.scaladsl._ val csv: BodyParser[Seq[Seq[String]]] = BodyParser { req => // A flow that splits the stream into CSV lines
val sink: Sink[ByteString, Future[Seq[Seq[String]]]] = Flow[ByteString]
// We split by the new line character, allowing a maximum of 1000 characters per line
.via(Framing.delimiter(ByteString("\n"), 1000, allowTruncation = true))
// Turn each line to a String and split it by commas
.map(_.utf8String.trim.split(",").toSeq)
// Now we fold it into a list
.toMat(Sink.fold(Seq.empty[Seq[String]])(_ :+ _))(Keep.right) // Convert the body to a Right either
Accumulator(sink).map(Right.apply)
}

PLAY2.6-SCALA(四) 请求体解析器的更多相关文章

  1. body-parser Node.js(Express) HTTP请求体解析中间件

    body-parser Node.js(Express) HTTP请求体解析中间件 2016年06月08日     781     声明 在HTTP请求中,POST.PUT和PATCH三种请求方法中包 ...

  2. body-parser 是一个Http请求体解析中间件

    1.这个模块提供以下解析器 (1) JSON body parser (2) Raw body parser (3)Text body parser (4)URL-encoded form body ...

  3. 爬虫笔记(四)------关于BeautifulSoup4解析器与编码

    前言:本机环境配置:ubuntu 14.10,python 2.7,BeautifulSoup4 一.解析器概述 如同前几章笔记,当我们输入: soup=BeautifulSoup(response. ...

  4. Solr系列五:solr搜索详解(solr搜索流程介绍、查询语法及解析器详解)

    一.solr搜索流程介绍 1. 前面我们已经学习过Lucene搜索的流程,让我们再来回顾一下 流程说明: 首先获取用户输入的查询串,使用查询解析器QueryParser解析查询串生成查询对象Query ...

  5. XML解析器(转)

    常见C/C++ XML解析器有tinyxml.XERCES.squashxml.xmlite.pugxml.libxml等等,这些解析器有些是支持多语言的,有些只是单纯C/C++的.如果你是第一次接触 ...

  6. 解析器组件和序列化组件(GET / POST 接口设计)

    前言 我们知道,Django无法处理 application/json 协议请求的数据,即,如果用户通application/json协议发送请求数据到达Django服务器,我们通过request.P ...

  7. python 之网页解析器

    一.什么是网页解析器 1.网页解析器名词解释 首先让我们来了解下,什么是网页解析器,简单的说就是用来解析html网页的工具,准确的说:它是一个HTML网页信息提取工具,就是从html网页中解析提取出“ ...

  8. XML的四种解析器(dom_sax_jdom_dom4j)原理及性能比较[收藏]

    1)DOM(JAXP Crimson解析器)    DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找特定 ...

  9. SpringMVC入门案例及请求流程图(关于处理器或视图解析器或处理器映射器等的初步配置)

    SpringMVC简介:SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 Spring结构图 Spr ...

随机推荐

  1. Activiti实战04_简单流程

    在Activiti实战03_Hello World中我们介绍了一个中间没有任何任务的流程,实现了流程的部署与查阅,而在本章中,将会为流程添加任务节点,是流程能够像个流程,变得更加丰满起来. 在上一节的 ...

  2. C# 统一对 try...catch 的调用,方便保存错误日志

    每个优秀的开发人员,应该尽可能保证程序稳定运行,在确实不需要使用try...catch的地方尽尽量不要使用以提高程序性能. 但是我们不可能保证每段代码不会出错,由于出错引起的用户界面并不友好,而且有可 ...

  3. css 一行或多行文字溢出以...的形式隐藏

    一行文字溢出以...形式隐藏 我需要隐藏... css代码如下: white-space:nowrap; text-overflow:ellipsis; overflow:hidden; 多行文字溢出 ...

  4. nfs服务安装配置

    一.准备阶段 配置解析主机 检查版本及内核 二.服务端安装 1) 配置yum把下载好的软件留着,下次备用,不用再下载 cachedir=/var/cache/yum/$basearch/$releas ...

  5. promise的实现方式和运行机制

    promise的规范其实种类很多,我们最常用的是promise/A+ 这篇文章会先将一个类似于promise的构造函数怎么写,网上很多教程并没有实现A+规范,只是看起来像而已 然后我们深入探究如何一步 ...

  6. 请问“javascript:;”是什么意思?

    请问“javascript:;”是什么意思?   最佳答案   就是 执行一段 空白JAVASCRIPT语句 并且返回的也是空或者false值..把 javascript:; 加在超级链接上 就可以防 ...

  7. 解决Cesium1.50对gltf2.0/3dtiles数据读取的问题

    问题说明 Cesium 1.50(2018/10/01)版本打开3dtiles可能会出现加载不上导致渲染停止的错误. 错误说明为:RuntimeError: Unsupported glTF Exte ...

  8. spring mvc 引入log4日记记录maven工程 slf4j和log4j输出到控制台配合使用log4j不输出到文件

    https://blog.csdn.net/qq_27093465/article/details/62928590 使用slf4j的优点: 提供带参数的日志输出方法(SLF4J 1.7及以后版本). ...

  9. 2019.10.21 csp-s模拟测试81 反思总结

    T1: 把每一行状压,按行DP.设fi,j,k,i表示第几行,j是当前行的1覆盖状态,k是当前行选择按钮的状态.转移的时候枚举j和k,再枚举下一层的按钮选择情况l.如果l和j可以全覆盖当前层则转移合法 ...

  10. python实例 文件处理

    对比Java,python的文本处理再次让人感动 #! /usr/bin/python spath="D:/download/baa.txt" f=open(spath," ...