PLAY2.6-SCALA(四) 请求体解析器
一个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/plain:
String, accessible viaasText. - application/json:
JsValue, accessible viaasJson. - application/xml, text/xml or application/XXX+xml:
scala.xml.NodeSeq, accessible viaasXml. - application/x-www-form-urlencoded:
Map[String, Seq[String]], accessible viaasFormUrlEncoded. - multipart/form-data:
MultipartFormData, accessible viaasMultipartFormData. - Any other content type:
RawBuffer, accessible viaasRaw.
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(四) 请求体解析器的更多相关文章
- body-parser Node.js(Express) HTTP请求体解析中间件
body-parser Node.js(Express) HTTP请求体解析中间件 2016年06月08日 781 声明 在HTTP请求中,POST.PUT和PATCH三种请求方法中包 ...
- body-parser 是一个Http请求体解析中间件
1.这个模块提供以下解析器 (1) JSON body parser (2) Raw body parser (3)Text body parser (4)URL-encoded form body ...
- 爬虫笔记(四)------关于BeautifulSoup4解析器与编码
前言:本机环境配置:ubuntu 14.10,python 2.7,BeautifulSoup4 一.解析器概述 如同前几章笔记,当我们输入: soup=BeautifulSoup(response. ...
- Solr系列五:solr搜索详解(solr搜索流程介绍、查询语法及解析器详解)
一.solr搜索流程介绍 1. 前面我们已经学习过Lucene搜索的流程,让我们再来回顾一下 流程说明: 首先获取用户输入的查询串,使用查询解析器QueryParser解析查询串生成查询对象Query ...
- XML解析器(转)
常见C/C++ XML解析器有tinyxml.XERCES.squashxml.xmlite.pugxml.libxml等等,这些解析器有些是支持多语言的,有些只是单纯C/C++的.如果你是第一次接触 ...
- 解析器组件和序列化组件(GET / POST 接口设计)
前言 我们知道,Django无法处理 application/json 协议请求的数据,即,如果用户通application/json协议发送请求数据到达Django服务器,我们通过request.P ...
- python 之网页解析器
一.什么是网页解析器 1.网页解析器名词解释 首先让我们来了解下,什么是网页解析器,简单的说就是用来解析html网页的工具,准确的说:它是一个HTML网页信息提取工具,就是从html网页中解析提取出“ ...
- XML的四种解析器(dom_sax_jdom_dom4j)原理及性能比较[收藏]
1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找特定 ...
- SpringMVC入门案例及请求流程图(关于处理器或视图解析器或处理器映射器等的初步配置)
SpringMVC简介:SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 Spring结构图 Spr ...
随机推荐
- SpringMVC配置顺序的问题
1:web.xml:web应用一经加载,先来找他 1):指明applicationContext的位置 2):引入spring监听,ContextLoaderListe ...
- Visual studio 编译错误 无法将文件obj\Debug\*.exe复制到bin\Debug\*.exe
问题: 错误 未能将“obj\Debug\Server.exe”复制到“bin\Debug\Server.exe”.超出了重试计数 10.失败. Server 错误 无法将文件“obj\Debug\S ...
- 搭建单向HTTPS
//参考网址:https://blog.csdn.net/haolipengzhanshen/article/details/51278262 //打开CMD窗口 cd C:\wamp\bin\apa ...
- for循环遍历json(附习题及答案)
三种方法 var mapColumn = { "vdoing" : "访问深度", "_visitorNumber": "访问量& ...
- 面试Mysql的几个常见问题
1.insert时如果数据重复如何用update? ,,) ; 2.一张表,里面有 ID 自增主键,当 insert 了 17 条记录之后,删除了第 15,16,17 条记录,再把 Mysql 重启, ...
- springmvc jsp向controller传参,一直为null
怎么检查都无解 重启电脑好了
- 关于python的列表操作(二):排序,统计
# 列表操作 num_list = [2, 5, 8, 6, 7, 9, 5, 7] # 升序 num_list.sort() print(num_list) # 降序 num_list.sort(r ...
- FreeMarker 获取页面request、session
使用Request里的Attribute值最简单的方法就是直接${AttributeName}或者安全一点:${AttributeName!"default Value"} 1.取 ...
- Oracle锁表查杀会话进程
一.逐条--锁表 (1)查表名 和 sessionidselect b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_obj ...
- GYM100741 A Queries
A. Queries time limit per test 0.25 s memory limit per test 64 MB input standard input output standa ...