如何在使用Joi验证请求时避免Hapi.js发送400错误

nel*_*nic 6 javascript validation node.js hapijs server

Hapi.js验证Joi + failAction问题.

情况

我们想要 使用Hapi构建一个" 传统的 " 服务器端 - 渲染的应用程序.

我试图了解如何避免 在验证失败时向客户端返回" 原始 " 400错误:Joi

寄存器的iphone4s-SIM

我们想拦截这个" 电子邮件不允许为空 " 验证错误并将其显示在html模板中返回给客户端,而不是简单地返回400错误.

@AdriVanHoudt建议我们应该:

"看看http://hapijs.com/api#route-options下的failAction "

所以我们添加failAction: 'log'/register路由处理程序:

{
  method: '*',
  path: '/register',
  config: {
    validate: {
      payload : register_fields,
      failAction: 'log'
    }
  },
  handler: register_handler
}
Run Code Online (Sandbox Code Playgroud)

请参阅以下代码: server.js

register_handler方法是:

function register_handler(request, reply, source, error) {
  console.log(request.payload);
  console.log(' - - - - - - - - - - - - - - - - - - - - -');
  console.log(source)
  console.log(' - - - - - - - - - - - - - - - - - - - - -');
  console.log(error)
  return reply('welcome!');
}
Run Code Online (Sandbox Code Playgroud)

我期待着看到一个错误的终端/主机,但是当我尝试console.loghandler:

- - - - - - - - - - - - - - - - - - - - -
undefined
- - - - - - - - - - - - - - - - - - - - -
undefined
Run Code Online (Sandbox Code Playgroud)

我在GitHub上问了一个问题:https://github.com/hapijs/joi/issues/725 但是还没有得到一个很好的 例子.如果您有时间帮助,请填写完整的代码:https://github.com/nelsonic/hapi-validation-question

nel*_*nic 9

两个简单的解决方案:

1.使用 server.ext('onPreResponse' ...

正如@Clarkie所述,捕获Hapi App中所有错误的一般方法是使用.'onPreResponse'

我们编写了一个Hapi插件,它正是这样做的:https://www.npmjs.com/package/hapi-error

像往常一样,它有:

建立状态 codecov.io 代码气候 依赖状态 devDependency Status HitCount

并允许您通过3个简单步骤定义自己的自定义错误页面.

1. 从npm 安装插件:

npm install hapi-error --save
Run Code Online (Sandbox Code Playgroud)

2.在Hapi项目中包含插件

在您register的服务器上包含插件:

有关简单示例,请参阅:/example/server_example.js

3.确保您有一个名为的视图 error_template

注意:hapi-error插件期望您正在使用Vision(Hapi应用程序的标准视图呈现库),它允许您为模板使用Handlebars,Jade,React等.

error_template.html(error_template.ext error_template.jsx)应该使用它将传递的3个变量:

  • errorTitle- Hapi生成的错误瓦片
  • statusCode-*HTTP的StatusCode发送到客户端如:404(未找到)
  • errorMessage- 人性化的错误消息

举个例子看: /example/error_template.html

就是这样!

高致病性禽流感发生误差屏

2.使用 failAction

建立状态 codecov.io 代码气候 HitCount

我们添加了failAction哪些重新使用,register_handler 以便registration-form.html显示任何输入验证错误消息(直到它与有效数据一起提交)

{
  method: '*',
  path: '/register',
  config: {
    validate: {
      payload : register_fields,
      failAction: register_handler // register_handler is dual-purpose (see below!)
    }
  },
  handler: register_handler
}
Run Code Online (Sandbox Code Playgroud)

register_handler方法是:

function register_handler(request, reply, source, error) {
  // show the registration form until its submitted correctly
  if(!request.payload || request.payload && error) {
    var errors, values; // return empty if not set.
    if(error && error.data) { // means the handler is dual-purpose
      errors = extract_validation_error(error); // the error field + message
      values = return_form_input_values(error); // avoid wiping form data
    }
    return reply.view('registration-form', {
      title  : 'Please Register ' + request.server.version,
      error  : errors, // error object used in html template
      values : values  // (escaped) values displayed in form inputs
    }).code(error ? 400 : 200); // HTTP status code depending on error
  }
  else { // once successful, show welcome message!
    return reply.view('welcome-message', {
      name   : validator.escape(request.payload.name),
      email  : validator.escape(request.payload.email)
    })
  }
}
Run Code Online (Sandbox Code Playgroud)

请参阅:server.js:57以获取完整文件.

其中extract_validation_error(error)return_form_input_values(error) 是在其中定义的辅助函数server.js(但将被拆分为可重用的视图助手),这使得我们的处理程序功能保持精简.

当我们提交没有任何必填字段的表单时,我们会看到:

寄存器1of4

寄存器3of4

我们还使用https://github.com/chriso/validator.js 来缓解Cross Site Scripting 漏洞:

寄存器下锅1of2

并在成功注册时显示欢迎信息: REG成功 -  1of2

结论

我们觉得重新使用处理函数作为将failAction 这个路由/动作相关的代码保存在一个地方,而server.ext('onPreResponse' ...(在适当的初始检查时)将引入" 钩子 ",这可能是一个混乱的来源(一旦一个应用程序有很多这样的挂钩...)

#YMMV

让我们知道您的想法! 加入https://gitter.im/dwyl/chat聊天


Cla*_*kie 5

您应该看一下在onPreResponse 扩展点中实现错误处理程序.

request.response中包含的响应可能会被修改(但不会分配新值).要返回不同的响应类型(例如,使用HTML响应替换错误),请通过回复(响应)返回新响应.请注意,调用reply(response)后生成的任何错误都不会传递回onPreResponse扩展方法以防止无限循环.

一个简单的例子:

server.ext('onPreResponse', function (request, reply) {
  if (request.response.statusCode === 400 ){
    return reply('summat else');
  }
  return reply.continue();
});
Run Code Online (Sandbox Code Playgroud)