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

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

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

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

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

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

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

现在的问题是,在这两种类型的验证失败后,我们如何通知用户?

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

解决方案 1 : 使用 HTTP 400 - Bad Request 表示业务失败

我们以相同的方式对待这 2 种类型的服务器端验证,当任何请求未通过任何验证时,我们会发回 HTTP 400,其中包含一个 json 对象,其中包含详细的错误消息,说明失败的原因。示例响应将是

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是和我们很不一样。这为前端创建了额外的工作,以区分 2 种类型的 HTTP 400 并以不同的方式处理它们。

建议重构我们的响应,而不是发送回 JSON 对象,我们发送回纯字符串 --- 基于 asp.net 框架/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

因此,在这两种情况下,站点用户在提交表单后都会看到一条错误消息,指出“银行帐户名称包含特殊字符”或“请求 header 太长”

解决方案 2:使用业务协议(protocol)而不是HTTP协议(protocol)

如果请求没有通过基本的服务器端验证,这只会发生在黑客身上,服务器会立即抛出异常,最终会得到 HTTP 500。一旦收到 HTTP 500,客户端就会简单地将用户引导到一个通用的错误页面,说些什么在没有任何详细信息的情况下发生了意外——我们尽量避免对黑客友好。

如果请求未通过高级服务器端验证,这可能发生在普通应用程序用户身上,服务器仍将返回 HTTP 200 - 成功,但使用不同的 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 协议(protocol)设计的,应该与您的业务逻辑无关。 HTTP 200 仅表示客户端已将请求发送到服务器,并且服务器已成功处理它返回响应。响应是否意味着交易已被批准,或交易已被拒绝,或者您提交的 BSB_Number 不存在,它根本不在乎。它不应该关心。

因此,如果交易确实被拒绝,或者表单有一些只能在服务器端检测到的无效输入,我们仍然应该响应 HTTP 200 但分配不同的 status_code,这相当于 HTTP 400,但是 ,它在我们的业务协议(protocol)中。因此,我们应该有效地将我们的业务协议(protocol)与 http 协议(protocol)区分开来,并且我们不能使用 HTTP FAILURE 来代表 BUSINESS 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”,我有点惊讶

    最佳答案

    在我看来,关注点分离应该是首要的。

    解决方案一,虽然说明错误源自业务层,但暗示表示存在错误。现在,错误的实际来源尚不明确。

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

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

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

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

    关于c# - 如何显示服务器端验证错误消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40166908/

    相关文章:

    asp.net - 关于 ASP.NET Web API RESTful 服务上的 OpenID/OAuth 的建议

    javascript - 使用 Kendo MVVM Dropdownlist 时如何强制选择第一项

    c# - pig 拉丁翻译崩溃C#

    c# - 在 JQuery 对话框内的文本框上初始化时,虚拟键盘 (Keith Wood) 会在每次单击时自行关闭

    asp.net - Unity 中的单例每次调用上下文(Web 请求)

    c# - 收获选择的插件无法显示 ASP.NET MVC 下拉列表的验证消息

    ASP.NET MVC 渲染模型作为隐藏字段

    c# - 通过 lambda 工厂与直接 "new Type()"语法创建对象

    c# - 在 C# 中向 Caller 方法发送异常

    c# - 编码变量参数 - __arglist 或替代