简体   繁体   English

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

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

Hapi.js Validation with Joi + failAction question. Hapi.js使用Joi + failAction验证。

Situation 情况

We want to build a " traditional " server-side - only rendered application using Hapi . 我们想要使用Hapi构建一个“ 传统的服务器端 - 渲染的应用程序。

I'm trying to understand how to avoid returning a " raw " 400 error to the client when Joi validation fails : 我正在尝试了解如何避免在Joi验证失败时向客户端返回“ 原始400错误:

寄存器的iphone4s-SIM

We want to intercept this " email not allowed to be empty " validation error and display it in the html template back to the client, instead of simply returning the 400 error. 我们想拦截这个“ 电子邮件不允许为空验证错误并将其显示在html模板中返回给客户端,而不是简单地返回400错误。

@AdriVanHoudt advised that we should: @AdriVanHoudt建议我们应该:

"Look at failAction under http://hapijs.com/api#route-options " “看看http://hapijs.com/api#route-options下的failAction”

So we added failAction: 'log' to the /register route handler: 所以我们将failAction: 'log'添加到/register路由处理程序:

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

See code in: server.js 请参阅以下代码: server.js

the register_handler is: 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!');
}

I am expecting to see an error in the terminal/console but when I try to console.log the handler : 我期待在终端/控制台中看到错误但是当我尝试console.log handler

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

I asked the question on GitHub: https://github.com/hapijs/joi/issues/725 but have not yet got an answer with a good example . 我在GitHub上问了一个问题: https//github.com/hapijs/joi/issues/725但是还没有得到一个很好的 例子 Full code if you have time to help: https://github.com/nelsonic/hapi-validation-question 如果您有时间帮助, 请填写完整的代码: https//github.com/nelsonic/hapi-validation-question

There are Two Simple Solutions: 两个简单的解决方案:

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

As noted by @Clarkie a generic way of catching all errors in your Hapi App is to use 'onPreResponse' . 正如@Clarkie所述,捕获Hapi App中所有错误的一般方法是使用'onPreResponse'

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

As usual it has : 像往常一样,它有

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

And lets you define your own custom error pages in 3 easy steps. 并允许您通过3个简单步骤定义自己的自定义错误页面。

1. Install the plugin from npm: 1.从npm安装插件

npm install hapi-error --save

2. Include the plugin in your Hapi project 2.在Hapi项目中包含插件

Include the plugin when you register your server: register服务器时包含插件:

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

3. Ensure that you have a View called error_template 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. 注意: hapi-error插件期望您使用VisionHapi应用程序的标准视图呈现库 ),它允许您为模板使用Handlebars,Jade,React等。

Your error_template.html ( or error_template.ext error_template.jsx ) should make use of the 3 variables it will be passed: 您的error_template.htmlerror_template.ext error_template.jsx )应该使用它将传递的3个变量:

  • errorTitle - the error tile generated by Hapi errorTitle - Hapi生成的错误 errorTitle
  • statusCode - *HTTP statusCode sent to the client eg: 404 ( not found ) statusCode - * HTTP statusCode发送到客户端, 例如: 404未找到
  • errorMessage - the human-friendly error message errorMessage - 人性化的错误消息

for an example see: /example/error_template.html 有关示例,请参阅: /example/error_template.html

That's it ! 就是这样

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

2. Use failAction 2.使用failAction

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

We added failAction which re-uses the register_handler so that the registration-form.html is shown with any input validation error message ( until it is submitted with valid data ) 我们添加了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
}

the register_handler is: 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. 请参阅: server.js :57以获取完整文件。

Where extract_validation_error(error) and return_form_input_values(error) are helper functions defined within server.js ( but would be split out into re-useable view helpers ) which keep our handler function lean. 其中extract_validation_error(error)return_form_input_values(error)是在server.js定义的辅助函数( 但会被拆分为可重用的视图助手 ),这使得我们的处理函数保持精简状态。

When we submit the form without any of the required fields we see: 当我们提交没有任何必填字段的表单时,我们会看到:

寄存器1of4

寄存器3of4

We also use https://github.com/chriso/validator.js to mitigate Cross Site Scripting vulnerability: 我们还使用https://github.com/chriso/validator.js来缓解Cross Site Scripting漏洞:

寄存器下锅1of2

And display a welcome message on successful registration: 并在成功注册时显示欢迎信息: REG成功 -  1of2

Conclusion 结论

We feel that re-using the handler function as the failAction keeps the code related to this route/action in a single place whereas server.ext('onPreResponse' ... ( while appropriate on initial inspection ) will introduce " hooks " which can be a source of confusion ( once an app has many such hooks... ) 我们觉得重新使用处理函数作为failAction将与此路由/操作相关的代码保存在一个单独的位置,而server.ext('onPreResponse' ...在初始检查时适当 )将引入“ 钩子 ”,它可以成为一个混乱的来源( 一旦一个应用程序有许多这样的钩子......

#YMMV #YMMV

Let us know what you think! 让我们知道您的想法! 加入https://gitter.im/dwyl/chat聊天

You should look at implementing an error handler in the onPreResponse extension point . 您应该查看在onPreResponse 扩展点上实现错误处理程序。

The response contained in request.response may be modified (but not assigned a new value). request.response中包含的响应可能会被修改(但不会分配新值)。 To return a different response type (for example, replace an error with an HTML response), return a new response via reply(response). 要返回不同的响应类型(例如,使用HTML响应替换错误),请通过回复(响应)返回新响应。 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. 请注意,调用reply(response)后生成的任何错误都不会传递回onPreResponse扩展方法以防止无限循环。

A simple example: 一个简单的例子:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM