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 ...
随机推荐
- 常用 docker 容器 使用
mongo: 单点 docker run -idt --name=mongo --restart=always -p : -v /home/hylas/opt/mongo/data:/data/db ...
- DVWA 之low级别sql注入
将Security level设为low,在左侧列表中选择“SQL Injection”,然后在右侧的“User ID”文本框中输入不同的数字就会显示相应的用户信息. 我们首先需要判断这里所传输的参数 ...
- if _name_ == " _main_"
1.作用 py文件有2种使用方法,第1是自己本脚本自己独立执行:第2是被import到其他文件脚本中执行. if _name_ == " _main_" 该语句控制其他下一步的脚 ...
- Python基础-列表、元组、字典、字符串(精简解析),全网最齐全。
一.列表 =====================================================1.列表的定义及格式: 列表是个有序的,可修改的,元素用逗号隔开,用中括号包围的序列 ...
- css3之文本和颜色功能之text-overflow,word-wrap
语法 text-overflow: clip|ellipsis|string; clip修剪文本.ellipsis显示省略符号来代表被修剪的文本.string使用给定的字符串来代表被修剪的文本. 效果 ...
- Tensorflow通过CNN实现MINST数据分类
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist = input_dat ...
- StoryBoard拆分(Storyboard References)
https://www.jianshu.com/p/78dc76204c8e iOS UI篇10- Storyboard(Storyboard Reference) https://www.aliyu ...
- Centos Apache 多站点配置
首先明白APACHE配置文件位置 /etc/httpd/ 系统会自动加载 "/etc/httpd/conf.d" 目录下面的 "*.conf"文件 创建多个 & ...
- 关于github 代码管理,协作开发
公司要用github 进行项目管理, 了解了一下github相关权限管理. 并做笔记如下: 个人账户可以建立公有/私有 repository , 公有的全天下的人都能看到,私有的全天下人都看不到 ...
- C# EventWaitHandle用法
waithander就是用来阻塞当前线程的,然后通过set()方法放开 namespace waithandler { class Program { //static EventWaitHandle ...