随着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请求中接下来会发生什么? 身体被接收。 因此,接收请求的函数必须返回消耗主体的东西。 这是一个迭代器,它是一个反应式流处理程序,在使用流后最终产生单个结果。 您不必为了了解过滤器而需要了解有关迭代操作方式的详细信息,需要了解的重要一点是,迭代最终会产生结果,您可以像使用将来那样使用其map函数进行map 。 有关编写迭代对象的详细信息,请阅读我的博客文章 。 HTTP请求中发生的下一件事是必须发送http响应。 那么iteratee的结果是什么? HTTP响应。 HTTP响应是一组响应标头,后跟一个响应正文。 响应主体是一个枚举器,它是一个反应流生成器。 所有这些都是在Plays EssentialAction特性中捕获的:

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

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

更简单的方法

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

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相关推荐

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

    api过滤器 随着Play 2.1的热销,很多人开始询问新的Play过滤器API. 实际上,API非常简单: trait EssentialFilter {def apply(next: Essent ...

  2. 直播播放器API(播放器调用方法、参数、接口和事件)

    直播播放器API(播放器调用方法.参数.接口和事件): 播放器调用方法 <div class="player"></div> <script src= ...

  3. Android SDK 提供的3套音频播放的API之玩转SoundPool,面试流程4轮技术面+1轮HR

    1.SoundPool的使用 1.1.准备音频资源 将准备的音频文放入assets文件夹下或者res下的raw文件夹下: assets下可以再新建文件夹批量加载,而raw只能同级存放单个加载: 在as ...

  4. QQ音乐播放地址 API 1

    效果以及原文: https://unnue.com/article/46 播放地址 https://api.bzqll.com/music/tencent/url?id=002GrJ771EmliH& ...

  5. 微信小程序音乐播放控制API在真机上貌似不可用?

    写了一个音乐播放页面,在IDE上调试正常,但是在真机上wx.getBackgroundAudioPlayerState()好像拿不到数据啊,seek也没有作用. 有哪位大神是运用正常的?求指点. 原文 ...

  6. [Android] [音视频系列]在 Android 平台使用 AudioRecord 和 AudioTrack API 完成音频 PCM 数据的采集和播放,并实现读写音频 wav 文件

    参考 官方文档地址:https://developer.android.google.cn/reference/android/media/AudioRecord GitHub 地址:https:// ...

  7. python刷新cdn_api 刷新是什么-和api 刷新相关的问题-阿里云开发者社区

    关于 api 刷新的搜索结果 回答 详细解答可以参考官方帮助文档 登陆CDN控制台,单击 刷新,进行刷新配置. URL刷新 原理:通过提供文件URL的方式,强制CDN节点回源拉取最新的文件. 任务生效 ...

  8. 【错误记录】Oboe / AAudio 播放器报错 ( onEventFromServer - AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared )

    文章目录 一.报错信息 二.解决方案 在 Android 8.0 以上的机型中 , Oboe 播放器调用的是 AAudio 播放器 API ; 在 Android 8.0 以上的机型中 , Oboe ...

  9. javaweb 中的过滤器 包装器

    过滤器要做的事情: 请求过滤器:完毕安全检查,又一次格式化请求首部或体.建立请求审计或日志 响应过滤器:     压缩响应流,追加或改动响应流创建一个全然不同的响应. 过滤器和servlet三个相似地 ...

最新文章

  1. 数据结构与算法 / 排序算法(2)
  2. python画图中grid等于true_Python中的matplotlib画图总结
  3. .NET架构小技巧(5)——反射,架构人员法宝III
  4. 【现代程序设计】【homework-07】
  5. 深度学习之 Cascade R-CNN
  6. SQL Server 2008 R2——ROW_NUMBER() 去掉不同行中相同列的重复内容
  7. python程序加密_Python简单的加密程序:如何循环Z回到A
  8. Fisco bcos 在多机器上搭建多个节点的区块链网络 教程
  9. php如何在sql语句中使用,php – 如何在SQL查询中使用数组
  10. 【狂神说Redis】5 事务
  11. stm32f4 USB项目开发详解
  12. PayPal开发前台生成订单和后台生成订单
  13. 视觉测量系统实现尺寸测量的4个步骤
  14. 局部线性嵌入 (Locally linear embedding-LLE)原理总结
  15. Ableton Live 10 Suite v10.1.42 WiN-MAC 音乐制作宿主软件
  16. mac pdf去水印_如何在Mac上为PDF添加水印
  17. HTML CSS添加阴影
  18. 【Windows8开发】关于WinRT组件,WinRT dll,Win32 dll,WinRT exe组件的一些尝试
  19. input输入框只能输入整数
  20. Windows 10 神州网信政府版 麦克风、摄像头的使用

热门文章

  1. impdp导入mysql_Oracle数据库的impdp导入操作以及dba_directories使用方法
  2. 匿名内部类与Lambda表达式
  3. 重新学习Spring一--Spring在web项目中的启动过程
  4. java 轻量级文件数据库_Java:如何创建轻量级数据库微服务
  5. hazelcast_Java:如何在不到5分钟的时间内通过Hazelcast提高生产力
  6. jpa root.join_JPA 2.1和Java EE 7中的JPQL增强功能(第1部分– JOIN ON)
  7. 设计模式示例_代理设计模式示例
  8. matchers依赖_Hamcrest Matchers教程
  9. java循坏_Java的坏功能是什么
  10. 使用适用于Java 2的AWS开发工具包的AWS DynamoDB版本字段