【发布时间】:2017-03-03 04:33:59
【问题描述】:
我们正在构建一个 Web 应用程序,但在前端显示服务器端验证错误消息时遇到了一些问题。
为了提供一些上下文,我们正在运行一个单页应用程序,其中前端在 react.js 中实现,后端 api 在 asp.net 中实现。我们的应用程序中有许多表单要求用户填写,我们计划在客户端和服务器端都实现表单验证。
我们现在的工作流程是先进行客户端验证,然后将数据传递给后端 api。然后后端将首先执行与前端相同的验证,以确保请求不是来自绕过客户端验证规则的恶意用户。对于来自正常通道的请求,它不应该在这一步失败,但是,如果它失败了,它只是意味着我们正在与黑客打交道。
但是,服务器端验证的内容远不止这些。有客户端不知道的信息,例如刚刚输入的银行账户用户是否存在于我们的数据库中? (我们没有专门的 api 来验证这一点,所以我们必须在用户将整个表单提交到服务器端后在表单级别执行此操作)。
因此,总而言之,服务器端验证规则有两个部分:与前端共享的基本验证规则,以及需要数据库访问的高级验证规则,该规则仅在服务器端可用。
现在的问题是,在用户未通过这两种类型的验证后,我们如何通知用户?
以下是我们目前提出的两个建议
解决方案 1:使用 HTTP 400 - Bad Request 表示业务失败
我们以相同的方式处理这两种服务器端验证,当任何请求未通过任何验证时,我们会发回 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
因此,在这两种情况下,网站用户在提交表单后都会看到一条错误消息,提示“银行帐户名称包含特殊字符”或“请求标头太长”
解决方案 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 来代表 BUSINESS FAILURE(2)。
以上是我对此的所有想法,我欢迎所有的cmets,关于这个话题的进一步讨论。
干杯, 博
(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”,我有点惊讶
【问题讨论】:
-
个人认为应该使用业务协议。 HTTP 协议错误准确地表明,这不是生成异常的原因。
标签: c# asp.net asp.net-mvc validation