api过滤器_了解播放过滤器API

api过滤器

随着Play 2.1的热销,很多人开始询问新的Play过滤器API。 实际上,API非常简单:

trait EssentialFilter {def apply(next: EssentialAction): EssentialAction
}

本质上,过滤器只是一个执行一个动作并返回另一个动作的函数。 过滤器通常会执行的操作是包装操作,并将其作为委托调用。 要将过滤器添加到应用程序中,只需将其添加到Global doFilter方法中即可。 我们提供了一个帮助类来帮助您:

object Global extends WithFilters(MyFilter) {...
}

容易吧? 包装动作,在全局中注册。 好吧,这很容易,但前提是您了解Play架构。 这非常重要,因为一旦您了解了Play的体系结构,便可以使用Play进行更多的工作。 我们这里有一些文档,从较高的层次解释了Play的体系结构。 在这篇博客文章中,我将在过滤器的上下文中解释Play的体系结构,并附带代码片段和用例。

Plays架构简介

我不需要在这里进行深入介绍,因为我已经提供了指向我们的体系结构文档的链接,但是简而言之,Play的体系结构与HTTP请求的流程非常匹配。 发出HTTP请求时到达的第一件事是请求标头。 因此,Play中的动作必须是接受请求标头的函数。 HTTP请求中接下来会发生什么? 身体被接收。 因此,接收请求的函数必须返回消耗主体的东西。 这是一个迭代器,它是一个React式流处理程序,在使用流后最终产生单个结果。 您不必为了了解过滤器而需要了解有关迭代操作方式的详细信息,需要了解的重要一点是,迭代最终会产生一个结果,您可以像使用将来的map功能那样进行map 。 有关编写迭代对象的详细信息,请阅读我的博客文章 。 HTTP请求中发生的下一件事是必须发送http响应。 那么iteratee的结果是什么? HTTP响应。 HTTP响应是一组响应标头,后跟一个响应正文。 响应主体是一个枚举器,它是一个React流生成器。 所有这些都体现在Plays EssentialAction特性中:

trait EssentialAction extends (RequestHeader => Iteratee[Array[Byte], Result])

这表明基本动作是一个函数,该函数采用请求标头并返回迭代器,该迭代器消耗字节数组主体块并最终产生结果。

更简单的方法

在继续之前,我想指出Play提供了一个名为Filter的辅助特性,它比使用EssentialFilter时使编写过滤器更容易。 这类似于Action特质,因为Action无需担心迭代和如何解析主体,从而简化了编写EssentialAction的过程,而只是提供了一个函数,该函数接受具有解析主体的请求,并返回结果。 Filter特质以类似的方式简化了事情,但是我将一直讲到最后,因为我认为最好在开始使用helper类之前先了解过滤器的工作原理。

Noop过滤器

为了演示过滤器的外观,我将展示的第一件事是noop过滤器:

class NoopFilter extends EssentialFilter {def apply(next: EssentialAction) = new EssentialAction {def apply(request: RequestHeader) = {next(request)}}
}

每次执行过滤器时,我们都会创建一个包装它的新EssentialAction 。 由于EssentialAction只是一个函数,我们可以通过传递传入的请求来调用它。 因此,以上是我们实现EssentialFilter基本模式。

处理请求头

假设我们要查看请求标头,然后根据我们检查的内容有条件地调用包装的操作。 可以做到这一点的过滤器示例可能是网站/admin区域的全面安全策略。 可能看起来像这样:

class AdminFilter extends EssentialFilter {def apply(next: EssentialAction) = new EssentialAction {def apply(request: RequestHeader) = {if (request.path.startsWith('/admin') && request.session.get('user').isEmpty) {Iteratee.ignore[Array[Byte]].map(_ => Results.Forbidden())} else {next(request)}}}
}

您可以在这里看到,由于我们是在解析正文之前拦截动作,因此在阻止动作时我们仍然需要提供一个正文解析器。 在这种情况下,我们将返回一个将仅忽略整个主体的主体解析器,并将其映射为禁止的结果。

处理身体

在某些情况下,您可能想对过滤器中的主体进行处理。 在某些情况下,您可能想解析正文。 如果是这种情况,请考虑改用动作合成 ,因为这样可以在动作解析正文之后挂接动作处理。 如果要在过滤器级别解析主体,则必须对其进行缓冲,解析,然后再次对其进行流传输以使动作再次解析。 但是,有些事情可以在过滤器级别轻松完成。 一个示例是gzip解压缩。 Play框架已经提供了开箱即用的gzip解压缩功能,但是如果不是这样,则可能是这样(使用我的play extra iteratees项目中的gunzip枚举):

class GunzipFilter extends EssentialFilter {def apply(next: EssentialAction) = new EssentialAction {def apply(request: RequestHeader) = {if (request.headers.get('Content-Encoding').exists(_ == 'gzip')) {Gzip.gunzip() &>> next(request)} else {next(request)}}}
}

在这里,我们使用iteratee组成将人体分析器iteratee包裹在gunzip枚举对象中。

处理响应头

当您进行过滤时,您通常会希望对正在发送的响应进行处理。 如果您只想添加标题,或向会话中添加内容,或对响应进行任何写操作,而无需实际读取它,那么这很简单。 例如,假设您要向每个响应添加一个自定义标头:

class SosFilter extends EssentialFilter {def apply(next: EssentialAction) = new EssentialAction {def apply(request: RequestHeader) = {next(request).map(result => result.withHeaders('X-Sos-Message' -> 'I'm trapped inside Play Framework please send help'))}}
}

使用处理身体的iteratee上的map函数,我们可以访问该动作产生的结果,然后可以按照演示进行修改。 但是,如果您想读取结果,则需要解开包装。 播放结果是AsyncResultPlainResult 。 一个AsyncResult是一个Result ,其中包含一个Future[Result] 。 它具有允许最终的PlainResult进行转换的transform方法。 PlainResult具有标题和正文。 假设您要向每个新创建的会话添加时间戳以记录创建时间。 可以这样完成:

class SessionTimestampFilter extends EssentialFilter {def apply(next: EssentialAction) = new EssentialAction {def apply(request: RequestHeader) = {def addTimestamp(result: PlainResult): Result = {val session = Session.decodeFromCookie(Cookies(result.header.headers.get(HeaderNames.COOKIE)).get(Session.COOKIE_NAME))if (!session.isEmpty) {result.withSession(session + ('timestamp' -> System.currentTimeMillis.toString))} else {result}}next(request).map {case plain: PlainResult => addTimestamp(plain)case async: AsyncResult => async.transform(addTimestamp)}}}
}

处理响应主体

您可能要做的最后一件事是转换响应主体。 PlainResult有两个实现, SimpleResult (用于没有传输编码的主体)和ChunkedResult (用于分块传输编码的主体)。 SimpleResult包含一个枚举器,而ChunkedResult包含一个接受迭代器以将结果写出的函数。 您可能要执行的操作示例是实现gzip过滤器。 一个非常幼稚的实现(例如,不要使用它,而是使用我的play iteratees项目中的完整实现),如下所示:

class GzipFilter extends EssentialFilter {def apply(next: EssentialAction) = new EssentialAction {def apply(request: RequestHeader) = {def gzipResult(result: PlainResult): Result = result match {case simple @ SimpleResult(header, content) => SimpleResult(header.copy(headers = (header.headers - 'Content-Length') + ('Content-Encoding' -> 'gzip')), content &> Enumeratee.map(a => simple.writeable.transform(a)) &> Gzip.gzip())}next(request).map {case plain: PlainResult => gzipResult(plain)case async: AsyncResult => async.transform(gzipResult)}}}
}

使用更简单的API

现在,您已经了解了如何使用基本的EssentialFilter API来实现所有目标,并希望因此了解了过滤器如何适应Play的体系结构以及如何利用它们来满足您的要求。 现在让我们看一下更简单的API:

trait Filter extends EssentialFilter {def apply(f: RequestHeader => Result)(rh: RequestHeader): Resultdef apply(next: EssentialAction): EssentialAction = {...}
}object Filter {def apply(filter: (RequestHeader => Result, RequestHeader) => Result): Filter = new Filter {def apply(f: RequestHeader => Result)(rh: RequestHeader): Result = filter(f,rh)}
}

简而言之,该API允许您编写过滤器而不必担心正文解析器。 它使动作看起来像是结果的请求标头的功能。 这限制了过滤器的全部功能,但是对于许多用例而言,您根本不需要此功能,因此使用此API提供了一种简单的替代方法。 为了演示,noop过滤器类如下所示:

class NoopFilter extends Filter {def apply(f: (RequestHeader) => Result)(rh: RequestHeader) = {f(rh)}
}

或者,使用“ Filter伴随对象:

val noopFilter = Filter { (next, req) =>next(req)
}

请求计时过滤器可能如下所示:

val timingFilter = Filter { (next, req) =>val start = System.currentTimeMillisdef logTime(result: PlainResult): Result = {Logger.info('Request took ' + (System.currentTimeMillis - start))result}next(req) match {case plain: PlainResult => logTime(plain)case async: AsyncResult => async.transform(logTime)}
}

参考: James and Beth Roper博客博客中的JCG合作伙伴 James Roper 了解了Play Filter API 。

翻译自: https://www.javacodegeeks.com/2013/02/understanding-the-play-filter-api.html

api过滤器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/350280.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML5中的webSocket、ajax、http

本文原链接:https://cloud.tencent.com/developer/article/1115496 https://cloud.tencent.com/developer/article/1193011 webSocket与ajax、web 一、webSocket与ajax 1、ajax2、webSocket二、webSocket API 1、事件2、方法3、属性4、常量三、webSocket与HTTP四、w…

动态规划,背包问题

背包问题模型,背包问题是一类整数规划问题,叙述如下:设有n件物品,并且第i件物品的重量为,其价值为,而背包能承受的总重量是,问应如何选择这些物品,才可以使背包中所装物品的价值最大…

routing zuul_尚学堂0131之zuul的相关概念及如何性能调优

采用服务名称指定路由方式1.1使用服务名称指定路由的规则是什么?1.2需改配置文件,将路由规则修改为使用服务名称路由。通过服务名, service-id为服务名zuul:routes:E-Book-Product-Provider:path: /suibian/**service-id: E-Book-Product-Provider路由的…

实时通信:使用Spring Boot实现Websocket

在开发Web应用程序时,有时我们需要将服务器事件下推到已连接的客户端。 但是,HTTP并非旨在允许这样做。 客户端打开与服务器的连接并请求数据。 服务器不会打开与客户端的连接并推送数据。 为了解决此限制,建立了一种轮询模式,其…

CUDA10.1配置VS2017

目录 一 CUDA 安装 二 CUDA环境变量配置 三 CUDA配置VS2017 一 CUDA 安装 1.1 CUDA下载 网址:https://developer.nvidia.com/cuda-toolkit-archive 可以根据需要下载不同版本的CUDA安装包。 1.2 CUDA安装 1.2.1 双击下载的.exe文件安装 1.2.2 点击‘OK’ 1.2…

鸿蒙应用开发 常用组件与布局

简介 HarmonyOS ArkUI 提供了丰富多样的 UI 组件,您可以使用这些组件轻松地编写出更加丰富、漂亮的界面。在本篇 Codelab 中,您将通过一个简单的购物社交应用示例,学习如何使用常用的基础组件和容器组件。本示例主要包含:“登录”…

[数论]莫比乌斯反演1

索引 莫比乌斯反演1 定理莫比乌斯反演2 证明莫比乌斯反演3 技巧前言 本篇内容全部为定理,无证明 定义 莫比乌斯函数的符号为\(\mu\),通俗的来讲\[ \mu(n) \left\{ \begin{matrix} 1 & n1\\ (-1)^k & n p_1p_2p_3\dots p_k\\ 0 & \text{其他…

怎么卸载光速头条_我用这三招,整理了桌面并且屏蔽了广告弹窗

这段时间,在用公司电脑工作时,有两个问题让我非常不爽。一是正处在专心工作中,突然桌面中间就弹出一个:天猫双12的广告,而且还没有关闭按钮。只能打开然后再关闭。二是每次打开电脑,桌面中间和右下角就有一…

Qt配置VS2017

目录 一 Qt安装 二 VS2017安装 三 Qt配置VS2017 一 Qt安装 1.1 下载网址:http://download.qt.io/archive/qt/ 这里选择 1.2 安装Qt 安装路径可以自己更改,然后点下一步 可以根据自己的VS版本自己选择,我们这里选MSVC-2017 64-bit 二…

opencv python tutorials_OpenCV-Python Tutorials 笔记(二)

OpenCV官方有一个面向python的文档OpenCV-PythonTutorials:我根据此文档进行了实践学习,结合自己经验简单记录一下笔记。(续)4、Image Processing inOpenCV4.1ChangingColorspaces转换颜色空间算是极其常用的操作了。不用说,cvtColor()。相关…

runltp出现问题 [

runltp 623行: if [ "$?" "0" ]; then 对[解析出了问题。 我灵机一动,是不是sh的问题。 which sh /bin/sh ls -l /bin/sh sh指向dash 果然不对 rm后 ln -s /bin/bash /bin/sh 再次运行,正确。 转载于:https://www.cnbl…

fork join框架_Java 7:Fork / Join框架示例

fork join框架Java 7中的Fork / Join Framework专为可分解为较小任务的工作而设计,并将这些任务的结果组合起来以产生最终结果。 通常,使用Fork / Join Framework的类遵循以下简单算法: // pseudocode Result solve(Problem problem) {if (p…

numpy T、transpose()函数、swapaxes()函数

目录 1 矩阵转置T,既线性代数中矩阵转置 2 transpose()函数 3 swapaxes()函数 1 矩阵转置T,既线性代数中矩阵转置 示例程序如下: import numpy as npa np.arange(0,24,2).reshape(3, 4)print(*****a****) print(a: \n, a) print(a.…

leetcode-54 螺旋矩阵

题目: 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。示例 1:输入:[[ 1, 2, 3 ],[ 4, 5, 6 ],[ 7, 8, 9 ]]输出: [1,2,3,6,9,8,7,4,5]示例 2:输入:[ [1, 2, 3, 4], [5, 6, 7, 8], [9,…

米线店结账程序 装饰着模式_实验报告2_装饰者模式

序号:姓名:杨林燕学号:106专业:软件工程日期:成绩:实验二装饰者模式的运用一、实验目的:装饰者模式动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的…

Java的内置垃圾收集如何使您的生活更美好(大部分时间)

通过从应用程序中学习企业APM产品,发现更快,更高效的性能监控。 参加AppDynamics APM导览! “无需为用户编写将寄存器返回到自由存储列表的程序。” 该行(以及随后的十几行)被埋在约翰麦卡锡(John McCart…

PyOpenCV 坐标系统

pyOpenCV中的坐标系统,以图片左上角为原点(0,0),水平方向为x轴(也既图像的宽度width),竖直方向为y轴(也既图像的高度height),如下图所示: #图像中…

office 论文 页码_毕业论文必备技巧:Word页码从第三页开始设置方法

许多应届毕业生在排版毕业论文时候,都会按要求设置页码,第一页是封面,第二页是目录,那么正文内容就要从第三页正式开始了。按照正规设置方式,那么页码此时应该是第三页。但是按照论文格式规定,页码应该是从…

散列

一.什么是散列 散列使用一个散列函数,将一个键映射到一个索引上。散列非常高效。使用散列将耗费O(1)时间来查找、插入、及删除一个元素。 映射表是一种用散列实现的数据结构,映射表是一种存储条目的容器,每个条目包含两个部分:一个…

移动端触摸(touch)事件

目有个交互需要实现手指滑动的交互,pc端使用mousedown,mousemove,mouseup监听实现。 但在ios设备上mousemove是不好监听的,同类的方法是touchstart,touchmove,touchend。 项目需求,需要用到拖动事件。由于不需要考虑IE8等低端浏览器的兼容性&…