验证器
AdonisJs 使得在 validation provider 的帮助下验证用户输入变得简单。
在本指南中,你将学习如何手动或通过路由验证器验证数据。
AdonisJs 验证器使用的是 Indicative 。有关完整用法的详细信息,请参阅官方文档。
建立
按照以下说明设置验证器。
首先,运行 adonis 命令以下载验证器提供程序:
adonis install @adonisjs/validator
然后,在 start/app.js文件中注册验证器提供程序:
const providers = [
'@adonisjs/validator/providers/ValidatorProvider'
]
验证用户输入
让我们从验证 HTML 表单收到的用户输入的示例开始:
<form method="POST" action="{{ route('UserController.store') }}">
<div>
<input type="text" name="email" />
</div>
<div>
<input type="text" name="password" />
</div>
<button type="submit"> Submit </button>
</form>
注册路由和控制器以处理表单提交的数据,并使用验证器验证数据:
Route.post('users', 'UserController.store')
const { validate } = use('Validator')
class UserController {
async store ({ request, session, response }) {
const rules = {
email: 'required|email|unique:users,email',
password: 'required'
}
const validation = await validate(request.all(), rules)
if (validation.fails()) {
session
.withErrors(validation.messages())
.flashExcept(['password'])
return response.redirect('back')
}
return 'Validation passed'
}
}
module.exports = UserController
让我们将上面的控制器代码分解为小步骤:
定义了 rules 规则
使用该 validate 方法根据规则验证所有请求数据。
如果验证失败,则清除所有错误并重定向回我们的表单。
显示闪存错误
我们可以修改HTML表单以显示我们的flash消息,这些消息在验证失败时设置:
<form method="POST" action="{{ route('UserController.store') }}">
<div>
<input type="text" name="email" value="{{ old('email', '') }}" />
{{ elIf('<span>$self</span>', getErrorFor('email'), hasErrorFor('email')) }}
</div>
<div>
<input type="text" name="password" />
{{ elIf('<span>$self</span>', getErrorFor('password'), hasErrorFor('password')) }}
</div>
<button type="submit"> Submit </button>
</form>
验证方法
以下是可用方法列表。
validate(data, rules, [messages], [formatter])
使用定义的规则验证数据:
const { validate } = use('Validator')
const validation = await validate(data, rules)
if (validation.fails()) {
return validation.messages()
}
你可以选择传递自定义错误消息,以在验证失败时作为第三个方法参数返回。
validateAll(data, rules, [messages], [formatter])
和 validate 一样,但是该 validate 方法在遇到第一个错误时就停止:
const { validateAll } = use('Validator')
const validation = await validateAll(data, rules)
sanitize(data, rules)
此方法返回通过验证的新对象:
const { sanitize } = use('Validator')
const data = sanitize(request.all(), rules)
sanitizor
Returns a reference to Indicative’s sanitizor:
const { sanitizor } = use('Validator')
const slug = sanitizor.slug('My first blog post')
这一句我还不是很理解,日后再说
formatters
Returns a reference to Indicative’s formatters:
const { formatters } = use('Validator')
validate(data, rules, messages, formatters.JsonApi)
路由验证器
数据验证通常发生在 HTTP 请求和响应生命周期中,你最终可以在每个控制器内编写相同的验证代码。
AdonisJs 路由验证器可以使验证的过程更简单:
// For a single route
Route
.post('users', 'UserController.store')
.validator('StoreUser')
// For a resourceful route
Route
.resource('users', 'UserController')
.validator(new Map([
[['users.store'], ['StoreUser']],
[['users.update'], ['UpdateUser']]
]))
验证器位于 app/Validators 目录内。 让我们使用以下 adonis 命令创建一个 StoreUser 验证器:
adonis make:validator StoreUser
该命令自动在 app/Validators 目录下生成一个 StoreUser.js。
现在,我们需要做的就是在验证器上定义我们的规则:
'use strict'
class StoreUser {
get rules () {
return {
email: 'required|email|unique:users',
password: 'required'
}
}
}
module.exports = StoreUser
如果验证失败,验证器会自动将错误设置为闪存消息,并将用户重定向回表单。
如果请求具有 Accept: application/json 标头,则响应将作为 JSON 发回。
自定义错误消息
默认错误消息可能会让用户感到困惑,因此需要创建自己的自定义验证错误消息。
AdonisJs 提供以下方法来实现。
只需在路由验证器上声明一个 messages 方法,并返回一个包含每条规则消息的对象,如下所示:
'use strict'
class StoreUser {
get rules () {
return {
email: 'required|email|unique:users',
password: 'required'
}
}
get messages () {
return {
'email.required': 'You must provide a email address.',
'email.email': 'You must provide a valid email address.',
'email.unique': 'This email is already registered.',
'password.required': 'You must provide a password'
}
}
}
module.exports = StoreUser
验证所有 要验证所有字段,设置一个 validateAll 方法,并且返回 true :
'use strict'
class StoreUser {
get validateAll () {
return true
}
}
module.exports = StoreUser
消除用户输入
你可以通过定义 sanitizationRules 在验证发生之前对请求数据执行的操作来过滤用户的输入:
class StoreUser {
get sanitizationRules () {
return {
email: 'normalize_email',
age: 'to_int'
}
}
}
module.exports = StoreUser
意思是将输入过来的 email 转化为 emial 格式,age 转化为整数
处理验证失败
由于每个应用程序的结构都不同,因此有时可能不希望自动处理错误。
你可以通过向 fails 验证器添加方法来手动处理故障:
class StoreUser {
async fails (errorMessages) {
return this.ctx.response.send(errorMessages)
}
}
module.exports = StoreUser
自定义数据对象
你可能希望验证不属于请求正文的自定义属性(例如,标题)。
这可以通过 data 在验证器类上定义属性来完成:
class StoreUser {
get rules () {
return {
sessionId: 'required'
}
}
get data () {
const requestBody = this.ctx.request.all()
const sessionId = this.ctx.request.header('X-Session-Id')
return Object.assign({}, requestBody, { sessionId })
}
}
module.exports = StoreUser
格式化
你还可以将 Indicative formatter 定义为 validator 类的属性:
const { formatters } = use('Validator')
class StoreUser {
get formatter () {
return formatters.JsonApi
}
}
授权
你可能希望执行检查以确保用户有权采取所需的操作。
这可以通过 authorize 在验证器类上定义一个方法来完成:
class StoreUser {
async authorize () {
if (!isAdmin) {
this.ctx.response.unauthorized('Not authorized')
return false
}
return true
}
}
module.exports = StoreUser
从 authorize 方法返回一个布尔值,告诉验证器是否将请求转发给控制器。
Request context
所有路由验证器都可以通过 this.ctx 访问当前 Request context 。
自定义规则
AdonisJs 支持所有 Indicative 验证,但也添加了一些自定义规则。
以下是自定义 AdonisJs 规则的列表。
unique(tableName, [fieldName], [ignoreField], [ignoreValue])
确保给定值对于给定的数据库表是唯一的:
'use strict'
class StoreUser {
get rules () {
return {
email: 'unique:users,email'
}
}
}
更新现有用户配置文件时,在执行 unique 规则时无需检查其电子邮件地址。这可以通过定义 ignoreField (id) 和 ignoreValue (userId) 来完成:
class StoreUser {
get rules () {
const userId = this.ctx.params.id
return {
email: `unique:users,email,id,${userId}`
}
}
}
扩展验证器
作为如何扩展 AdonisJs 的示例 Validator,首先添加一个新规则,以确保在向数据库添加新评论时存在帖子。
我们称这个规则为 exists :
const Validator = use('Validator')
const Database = use('Database')
const existsFn = async (data, field, message, args, get) => {
const value = get(data, field)
if (!value) {
/**
* skip validation if value is not defined. `required` rule
* should take care of it.
*/
return
}
const [table, column] = args
const row = await Database.table(table).where(column, value).first()
if (!row) {
throw message
}
}
Validator.extend('exists', existsFn)
我们可以使用我们的新 exists 规则:
get rules () {
return {
post_id: 'exists:posts,id'
}
}
由于要扩展的代码 Validator 只需执行一次,因此你可以使用 Provider 或 Ignitor hooks 来执行此操作。阅读 Extending the Core 以获取更多信息。