如何显示服务器端验证错误消息?

时间:2016-10-21 01:21:47

标签: c# asp.net asp.net-mvc validation

我们正在构建一个Web应用程序,我们在前端显示服务器端验证错误消息时遇到了一些问题。

为了给出一些上下文,我们正在运行单页面应用程序,其中前端在asp.net中的react.js和backend api中实现。我们的应用程序中有许多表单要求用户填写,我们计划在客户端和服务器端实现表单验证。

我们现在的工作流程是首先进行客户端验证,然后将数据传递给后端api。然后后端将首先执行相同的验证前端,以确保请求不是来自绕过客户端验证规则的恶意用户。对于来自普通频道的请求,它应该永远不会失败,如果确实如此,它只是意味着我们正在与黑客打交道。

但是,在服务器端验证方面还有一些问题。有客户方不知道的信息,例如,是刚刚输入的银行帐户用户存在于我们的数据库中? (我们没有专门的api来验证这一点,因此我们必须在用户将整个表单提交给服务器端后在表单级别执行此操作。)

总而言之,服务器端验证规则有两部分:与前端共享的基本验证规则,以及需要数据库访问的高级验证规则,这些规则仅在服务器端可用。

现在的问题是,我们如何在他们未通过这两种验证后通知用户?

以下是我们迄今为止提出的两项建议

解决方案1 ​​:使用HTTP 400 - 错误请求来表示业务失败

我们以相同的方式处理这两种类型的服务器端验证,当任何请求未通过验证时,我们发回一个带有json对象的HTTP 400,其中包含详细的错误消息,说明它失败的原因。样本回复将是

HTTP 400 Bad Request
{
      "bsb_name" :"bsb_name has special characters",          
      "bsb_number":"bsb number doesn't exist",
      "amount":"amount is required"
 }

现在的问题是,我们不是唯一可以返回HTTP 400的一方。由于我们使用的是asp.net框架加上OWIN框架,框架本身也可以在某种情况下发回HTTP 400,而HTTP 400他们发送的与我们截然不同。这为前端创建了额外的工作,以区分两种类型的HTTP 400并以不同的方式处理它们。

建议重新考虑我们的响应,而不是发送回JSON对象,我们发送回普通字符串---基于asp.net framework / owin将以纯字符串发回HTTP 400的假设(1)。所以在前端我们没有区分它们并且可以以相同的方式处理它们。此外,为了避免引入魔术分隔符,我们只返回第一个错误消息文本而不是所有文本。所以样本响应可能是

HTTP 400 Bad Request
"Bank account name has special characters" 

我们将以与asp.net框架返回的HTTP 400相同的方式对待它,比方说,

HTTP 400 Bad Request
Request header too long

因此,在这两种情况下,网站用户在提交表单后都会看到错误消息"银行帐户名称有特殊字符"或者"请求标题太长"

解决方案 2:使用业务协议而非HTTP协议

如果请求未通过基本服务器端验证(这只会发生在黑客身上),服务器会立即抛出异常,最终会出现HTTP 500.一旦收到HTTP 500,客户端就会直接将用户引向一般错误页面说出意外的事情没有任何详细信息 - 我们试图避免被黑客友好。

如果请求未通过高级服务器端验证(这可能发生在普通应用程序用户身上),服务器仍将返回HTTP 200 - Success,但使用不同的status_code表示这是一个错误响应。例如

  HTTP 200 Success
  {
       status_code: Err_123
       error_message: "bsb doesn't exist"
  }

我个人想要使用解决方案2,但被告知我们不应该使用HTTP 200来验证错误。由于HTTP 200代表OK,在服务器端验证失败的情况下使用HTTP 200是没有意义的。

我的理解是,HTTP状态代码是为HTTP协议设计的,应该与您的业务逻辑无关。 HTTP 200仅表示客户端已将请求发送到服务器,并且服务器已成功处理它返回响应。无论回复意味着交易已被批准,还是交易被拒绝,或者您提交的BSB_Number不存在,它根本不关心。它不应该在乎。

因此,如果事务被拒绝,或者表单有一些只能在服务器端检测到的无效输入,我们仍然应该响应HTTP 200但是分配一个不同的status_code,相当于HTTP 400, ,它在我们的商业协议中。如此有效,我们应该将我们的业务协议与http协议区分开来,我们不能使用HTTP FAILURE来代表业务失败(2)。

以上是我对此的全部想法,我欢迎所有评论,进一步讨论这个主题。

干杯, 博

  • (1):假设是错误的,因为我最近发现IIS在某些情况下可以返回HTTP 400。当发生这种情况时,它会返回一个HTML页面。

  • (2):类比可以是

**IP -- TCP -- HTTP -- BUSINESS** If TCP layer fails, IP shouldn't be concerned; If HTTP layer fails, TCP shouldn't be concerned; If BUSINESS layer fails, HTTP shouldn't be concerned;

不是分开关注'编程中的常识??当看到有人说"在出现业务失败的情况下返回HTTP 400时,我会感到有些惊讶"

4 个答案:

答案 0 :(得分:2)

在我看来,首先应该首先分离关注点。

解决方案一,虽然说明错误源自业务层,但意味着表示有问题。现在,对于错误实际起源的位置,它是模棱两可的。

另一方面,解决方案2详细说明HTTP事务是成功的,并且业务逻辑响应错误。

理想情况下(在我看来)服务器端的所有错误都应该被捕获并报告为业务逻辑中的错误,因此只有当用户请求错误或敏感页面时才会抛出HTTP错误。

这会导致系统更优雅地失败,并使其更具可扩展性。 (例如,如果您在其他地方实施API,则不需要在其中包含HTTP错误处理,只显示所述错误)

顺便说一下,这可能更适合P.SE而不是SO。

答案 1 :(得分:0)

我的解决方案类似于解决方案2.我将实体定义为所有RESTful请求的响应。

JTextField

请求是成功还是失败,前面会得到一个实体并检查代码。如果代码为200(或其他定义的代码),则继续处理内容,否则显示消息并返回。

答案 2 :(得分:0)

  

对于来自普通频道的请求,它应该永远不会失败,如果确实如此,它只是意味着我们正在与黑客打交道。

如果您的API是公开的,为什么不使用状态代码500,...这是一种欺骗人们尝试访问您的API的方法。但是,您现在如果这不是内部服务器错误,带有读取状态消息。或you use Status Code 202(请求已被接受处理,但处理尚未完成。请求最终可能会或可能不会被执行,因为在实际处理时可能不允许该请求。 status从异步操作返回,例如。)

如果您使用状态代码200或400,并且每个人都知道是否可以注入......但是,由您决定,这只是我的建议,就像您需要的意见一样。

答案 3 :(得分:0)

在我看来,您的400响应代码是可以的。实际上,您需要对如何响应验证方案进行建模。例如,BaseResponse.cs看起来像这样。

public class BaseResponse<T> where T: object {
  public T Data {get;set;}
  public bool Success {get; set;}
  public IList<Error> Errors {get;set;}
}

另一方面,您可以按如下方式定义错误类

public class Error {
   string Type {get;set;} // "validation", "business"
   string Code {get;set;} // "VAL_1234", "BIZ_4321"
   string Message {get;set;} // "Value should be greater than 10"
}

现在在反应应用程序的Javascript端,您的代码并不复杂

fetch(url)
.then((response)=> {
  if(response.status === 400) {
     let json = response.json();
     if(json) { // you have validation errors, do something with errors property in json
     }else {  // 400 was returned because of some other reason
     }
  }
});

与上述内容相结合的更具参与性的解决方案应该有效。样本here