本章将讲解 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
Request
as 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://hzways.gitee.io/p/beeb0951.html
版权声明: 转载请注明出处.