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

How to avoid Hapi.js sending 400 error when Validating Request with Joi

Hapi.js 使用 Joi + failAction 问题进行验证。

情况

我们想构建一个“传统服务器端- 使用 Hapi.

呈现的应用程序

我正在尝试了解如何避免返回“raw400Joi 验证 失败时客户端出错 :

我们要拦截这个“email not allowed to be emptyvalidation error并显示在html模板返回给客户端, 而不是简单地返回 400 错误。

@AdriVanHoudt建议我们应该:

"Look at failAction under http://hapijs.com/api#route-options "

因此我们将 failAction: 'log' 添加到 /register 路由处理程序:

{
  method: '*',
  path: '/register',
  config: {
    validate: {
      payload : register_fields,
      failAction: 'log'
    }
  },
  handler: register_handler
}

见代码: 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!');
}

我希望在 terminal/console 中看到错误 但是当我尝试 console.loghandler :

- - - - - - - - - - - - - - - - - - - - -
undefined
- - - - - - - - - - - - - - - - - - - - -
undefined

我在 GitHub 上问了这个问题:https://github.com/hapijs/joi/issues/725 但还没有得到 good example 的答案。 如果您有时间提供帮助,请提供完整代码:https://github.com/nelsonic/hapi-validation-question

您应该查看 onPreResponse extension point 中的错误处理程序。

The response contained in request.response may be modified (but not assigned a new value). To return a different response type (for example, replace an error with an HTML response), return a new response via reply(response). Note that any errors generated after reply(response) is called will not be passed back to the onPreResponse extension method to prevent an infinite loop.

一个简单的例子:

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

两个简单的解决方案:

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

正如@Clarkie 所指出的,在您的 Hapi 应用程序中捕获 所有 错误的 通用 方法是使用 'onPreResponse'

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

和往常一样:

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

1。从 npm:

安装 plugin
npm install hapi-error --save

2。在你的 Hapi 项目中包含插件

当您 register 您的服务器时包含插件:

See: /example/server_example.js for simple example

3。确保您有一个名为 error_template

的视图

Note: hapi-error plugin expects you are using Vision (the standard view rendering library for Hapi apps) which allows you to use Handlebars, Jade, React, etc. for your templates.

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

  • errorTitle - Hapi生成的错误tile
  • statusCode - *HTTP statusCode 发送给客户端例如:404未找到
  • errorMessage - human-friendly 错误信息

for an example see: /example/error_template.html

就是这样

2。使用 failAction

我们添加了 failAction 其中 re-uses 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
}

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)
    })
  }
}

See: server.js:57 for complete file.

其中 extract_validation_error(error)return_form_input_values(error) 是在 server.js 中定义的辅助函数( 但会拆分成 re-useable 视图助手 ),这使我们的处理函数保持精简。

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

我们也用https://github.com/chriso/validator.js 减轻 Cross Site Scripting 漏洞:

并在注册成功时显示欢迎信息:

结论

我们认为 re-using 处理函数作为 failAction 将与此 route/action 相关的代码保存在一个地方 而 server.ext('onPreResponse' ...虽然适合初始检查)将引入“hooks可能会造成混淆(一旦一个应用有很多这样的钩子...

#YMMV

让我们知道您的想法!