本章将讲解 Action 的组成和原理,并且介绍了几种定义通用 Action 的方法。
Action composition
Action 组成结构
Custom action builders
自定义 action builders
我们有多种方法来声明一个Action,使用request参数,不使用request参数, 使用body parser等等。实际上,并不止这些,我们将在异步编程一节进行讲述。
这些用于构建 actions 的方法实际上都是由一个名为 ActionBuilder 的 trait 定义的。而我们用来声明 Action 的 Action Object 只是这个 trait 的一个实例。通过实现自己的 ActionBuilder,您可以声明可重用的 action stack,然后可以使用它们来构建 actions。
让我们从日志修饰符(logging decorator) 的简单示例开始,我们希望记录对 action 的每次调用日志。
第一种方法是在 invokeBlock 方法中实现这个功能,ActionBuilder 构建的每一个 action 都会调用这个方法。
1 | import play.api.mvc._ |
现在,我们可以在 controllers 中使用依赖注入来获取 LoggingAction 的一个实例,并且以使用普通 Action 的方式来使用它。
1 | class MyController @Inject()(loggingAction: LoggingAction, |
Since ActionBuilder provides all the different methods of building actions, this also works with, for example, declaring a custom body parser:
由于 ActionBuilder 提供了创建 actions 所有不同的方法,所以我们也可以在自定义的 Action 中使用 body parser 等普通 Action 的功能。
1 | def submit = loggingAction(parse.text) { request => |
组合 actions
Composing actions
在大多数应用程序中,我们希望有多个 action builders, 比如一些做不同类型的 authentication, 一些提供不同类型的通用功能组件,等等。
在这种情况下,我们不想为每一个 action builder 重写 loggingAction,我们需要定义一个可重用的方式来简化代码。可重用的操作代码可以通过包装操作(wrapping actions)来实现
1 | import play.api.mvc._ |
We can also use the Action action builder to build actions without defining our own action class:
我们也可以使用 Action action builder 来 创建 actions 而不需要定义我们自己的 action class
1 | import play.api.mvc._ |
可以使用 composeAction 方法将 Action 混合到 action builders 中
1 | class LoggingAction @Inject() (parser: BodyParsers.Default)(implicit ec: ExecutionContext) extends ActionBuilderImpl(parser) { |
通过这样 code 后使用,效果和之前的例子一样
1 | def index = loggingAction { |
我们也可以在不使用 action builder 的情况下将 action 混合到 wrapping actions 中
1 | def index = Logging { |
More complicated actions
更复杂的 Action
到目前为止,我们只展示了完全不会影响请求的 actions。当然,我们也可以对传入的请求对象进行读取和修改。
1 | import play.api.mvc._ |
Note: Play already has built in support for X-Forwarded-For headers.
我们可以 block 请求
1 | import play.api.mvc._ |
最后我们还能修改返回的结果
1 | import play.api.mvc._ |
Different request types
不同的请求类型
虽然 action composition 允许您在 HTTP request 和 response 级别执行额外的处理,但是您通常希望构建数据转换管道( pipelines),以便向请求本身添加上下文(context) 或 执行验证(perfom validation)。
ActionFunction 可以看作是作用在 request 上的一个函数,在输入请求类型和传递到下一层的输出类型上都参数化。
每个操作函数都可以表示模块处理,例如身份验证、对象的数据库查找、权限检查或希望跨操作组合和重用的其他操作。
一些实现了实现 ActionFunction 的预定义的 trait 对于不同类型的处理非常有用。
ActionTransformer- can change the request, for example by adding additional information.
- 可以改变一个请求,例如为此请求添加额外信息等。
ActionFilter- can selectively intercept requests, for example to produce errors, without changing the request value.
- 可以选择性的拦截请求,例如在不改变请求的前提下产生一个错误。
ActionRefiner- is the general case of both of the above.
- 上面两个 trait 的通用父类(trait)。
ActionBuilder- is the special case of functions that take
Requestas input, and thus can build actions. - 以 “
Request“ 作为输入的函数的一种特殊情况,并且是否可以构建 actions。
- is the special case of functions that take
1 | trait ActionRefiner[-R[_], +P[_]] extends ActionFunction[R, P] { |
我们还可以通过实现 invokeBlock 方法定义自己的 ActionFunction。这样通常可以方便地创建请求的输入和输出类型实例(使用 WrappedRequest),但这并不是严格必需的。
Authentication
action functions最常见的用例之一是身份验证。我们可以很容易地实现我们自己的身份验证操作转换器,它从原始请求确定用户并将其添加到新的UserRequest。注意,这也是一个ActionBuilder,因为它接受一个简单的请求作为输入
1 | import play.api.mvc._ |
内置的 authentication action builder 只是一个方便的帮助程序,它可以最小化实现简单情况下身份验证所需的代码,其实现与上面的示例非常相似。
由于编写自己的身份验证帮助程序很简单,所以如果内置的帮助程序不适合您的需要,我们建议这样做。
原文链接: https://www.317318.xyz/p/beeb0951.html
版权声明: 转载请注明出处.