我应该使用HTTP 4xx来表示HTML表单错误吗?

8
我刚花了20分钟来调试一些(django)单元测试。我正在测试一个视图POST,期望得到302返回代码,之后我断言许多数据库实体与预期相同。结果最近合并的提交添加了一个新的表单字段,我的测试失败了,因为我没有包含正确的表单数据。
问题在于测试失败,因为HTTP返回代码是200,而不是302,我只能通过打印响应HTTP并查看其中的内容来解决问题。除了必须查看HTML以解决问题的烦恼外,200似乎对于未被处理的POST来说是错误的代码。4xx(客户端错误)似乎更合适。此外,如果使用422(无法处理的实体)作为REST API中可能的返回代码,将会使测试调试变得轻松,因为响应代码将直接指向问题。
我已经阅读过在REST API中使用422作为可能的返回代码,但找不到在HTML视图/处理程序中使用它的任何证据。
我的问题是 - 还有其他人这样做吗?如果没有,为什么没有?
[更新1]
只是澄清一下,这个问题与HTML表单有关,而不是API。
这也是关于HTTP响应代码本身的问题,而不是Django。我已经移除了django标签。
【更新2】
进一步澄清,附带W3C参考资料(http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html):
10.2 成功的2xx
这类状态码表示客户端的请求已成功接收、理解和接受。
10.4 客户端错误4xx
状态码4xx旨在处理客户端似乎出错的情况。
10.4.1 400 Bad Request
由于格式不正确,服务器无法理解该请求。

https://www.rfc-editor.org/rfc/rfc4918#page-78中得知:

11.2. 422无法处理的实体

422无法处理的实体状态码表示服务器理解了请求实体的内容类型(因此不适用415(不支持的媒体类型)状态码),并且请求实体的语法正确(因此不适用400(错误请求)状态码),但是无法处理包含的指令。例如,如果XML请求正文包含格式良好(即语法正确)但语义上错误的XML指令,则可能发生此错误条件。

[更新3]

深挖后发现,422是WebDAV扩展[1],这可能解释了它的神秘性质。话虽如此,由于Twitter将420用于自己的目的,因此我认为我可以随便使用。但它将以4开头。

[更新4]

关于自定义响应代码的使用说明,以及它们应该如何处理(如果未被识别),来自HTTP 1.1规范(https://www.rfc-editor.org/rfc/rfc2616#section-6.1.1):
HTTP状态码是可扩展的。HTTP应用程序不需要理解所有注册状态码的含义,尽管这样的理解显然是可取的。但是,应用程序必须理解任何状态码的类别,如第一个数字所示,并将任何无法识别的响应视为该类别的x00状态码的等效项,但未识别的响应不能被缓存。例如,如果客户端收到了431的无法识别的状态码,则可以安全地假设其请求存在问题,并将响应视为收到了400状态码。在这种情况下,用户代理应向用户呈现随响应返回的实体,因为该实体很可能包含人类可读的信息,可以解释异常的状态。

[1] https://www.rfc-editor.org/rfc/rfc4918


[1] {{链接1:https://www.rfc-editor.org/rfc/rfc4918}}

1
这真的取决于您如何设计您的API。我不确定422是否是最好的响应代码,但是当然,在4xx范围内,您可以发送其他内容而不是200。 - Matt Ball
@MattBall 出于好奇 - 你为什么认为这不是最好的代码?(我也没有答案 - 但以4开头的东西比2更好)? - Hugo Rodger-Brown
不是直接回答你的问题,但是可以参考https://dev59.com/a3I-5IYBdhLWcg3wO1rl。 - Matt Ball
是的 - 看过那个答案了 - 但不幸的是我不同意被接受的答案 ;-) (请参见上面问题的更新)。 - Hugo Rodger-Brown
仅供参考 - RFC2616已被RFC7230(和相关规范)所取代,因此最好参考它们。请参见http://httpwg.org/specs/。另外,尽管Twitter最初使用了420,但一旦定义了标准的429,他们就转而使用了它。 - Mark Nottingham
4个回答

2

如果结果不是成功的话,那么200是错误的。

我也认为成功重定向到结果页面应该是303,而不是302。

客户端错误应该使用4xx,422对我来说是正确的。无论如何,不要在没有通过IANA注册的情况下发明新的4xx代码。


我对422的保留意见仅在于它不在原始的W3C规范中,而是一个WebDAV扩展。我选择421的原因是422是最接近的现有代码,而420是Twitter的虚构代码,所以它们之间的一半似乎是合适的。 - Hugo Rodger-Brown
同样地 - 虽然我理解“不要自己发明东西”的情绪,但在实际操作中,最坏的情况是什么(这是一个真正的问题,我并非故意挑衅)。 - Hugo Rodger-Brown
a) HTTP/1.1是IETF规范,而不是W3C规范。 b) 该规范未列出所有状态码,可以在http://www.iana.org/assignments/http-status-codes/http-status-codes.xml上找到一个注册表。 c) 定义位于WebDAV规范中并不相关;422是一种通用的状态码。 d) 最糟糕的情况是有人定义了421并使其流行,而其定义与你的定义冲突。顺便提一下,谷歌遇到了状态码308的问题。 - Julian Reschke
(注:针对我们特定情况我将坚持使用421,但如果有未来的下游问题我会承担全部责任;-)) - Hugo Rodger-Brown
我明白了,它是422状态码。请参考http://tech.yunojuno.com/whats-in-a-http-status-code.html。 - Hugo Rodger-Brown
显示剩余3条评论

2
显然,某些表单POST请求应该导致4xx HTTP错误(例如错误的URL,缺少预期字段,未能发送身份验证cookie),但是在应用程序中,输错密码或意外省略必填字段是非常常见和预期的情况。从任何规范中都不清楚每个表单无效问题都必须构成HTTP错误。
我猜我的直觉是,如果服务器向客户端发送一个表单,并且客户端立即用所有预期的字段正确形成的POST请求对该表单进行回复,则普通业务逻辑违规不应该是HTTP错误。
如果客户端脚本使用HTTP作为传输机制,则情况似乎更不明确。例如,如果JSON-RPC请求发送表单详细信息,则成功调用服务器端函数并将响应返回给调用者,似乎是200成功。
据说:使用错误凭据登录Facebook、Google和Wikipedia会得到200,而Amazon则是204。
理想情况下,IETF将通过RFC澄清这一点,可能添加一个HTTP错误代码,表示“由于表单无效而未执行操作”,或扩展422的定义以涵盖此内容。

这并不明显,因此才会有问题。 - Bobort

1
目前似乎没有被接受的答案,说实话,这有点令人惊讶。表单验证是Web开发的基石,事实上不存在用于说明验证失败的响应代码似乎是一个错失的机会。特别是考虑到自动化测试的普及。检查HTML内容以获取错误消息而不是仅测试响应代码来测试响应似乎不太实用。
我坚持在问题中的断言,即200是请求失败的业务规则的错误响应代码,而302也不适当。(如果表单验证失败,则不应更新服务器上的任何状态,因此具有幂等性,并且无需使用PRG模式防止用户重新提交表单。让他们提交。)
所以,鉴于没有“批准”的方法,我目前正在使用自己的方法进行测试(字面意思),即421。如果我们使用非标准HTTP状态代码遇到任何问题,我会回报的。
如果此答案没有更新,则我们正在生产中使用它,它有效,您也可以这样做。

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接