8

我只花了 20 分钟调试一些 (django) 单元测试。我正在测试一个视图 POST,我期待一个 302 返回码,之后我断言一堆数据库实体符合预期。原来最近合并的提交添加了一个新的表单字段,我的测试失败了,因为我没有包含正确的表单数据。

问题是测试失败了,因为 HTTP 返回码是 200,而不是 302,我只能通过打印响应 HTTP 并查看它来解决问题。除了必须通过 HTML 来解决问题的烦恼之外,对于未处理的 POST,200 似乎是错误的代码。4xx(客户端错误)似乎更合适。此外,它会使调试测试变得轻而易举,因为响应代码会直接指出问题所在。

我已经阅读了有关在 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 错误请求

由于语法错误,服务器无法理解该请求。

并来自https://www.rfc-editor.org/rfc/rfc4918#page-78

11.2. 422 无法处理的实体

422(Unprocessable Entity)状态码意味着服务器理解请求实体的内容类型(因此 415(Unsupported Media Type)状态码是不合适的),并且请求实体的语法是正确的(因此是 400(Bad Request) ) 状态码不合适)但无法处理包含的指令。例如,如果 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

4

4 回答 4

2

如果结果不是成功,你是对的,200 是错误的。

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

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

于 2013-03-27T16:12:04.883 回答
2

很明显,某些表单 POST 请求会导致 4xx HTTP 错误(例如,错误的 URL、缺少预期的字段、无法发送 auth cookie),但错误输入密码或意外遗漏必填字段在应用程序中是极其常见和预期的情况。

任何规范似乎都不清楚每个表单失效问题都必须构成 HTTP 错误。

我想我的直觉是,如果服务器向客户端发送一个表单,并且客户端立即使用格式正确的 POST 请求回复该表单,并包含所有预期的字段,那么常见的业务逻辑违规不应该是 HTTP 错误。

如果客户端脚本使用 HTTP 作为传输机制,情况似乎就更不明确了。例如,如果 JSON-RPC 请求发送表单详细信息,则成功调用服务器端函数并将响应返回给调用者,看起来像是 200 成功。

有趣的是:使用错误凭据登录会从 Facebook、Google 和 Wikipedia 获得 200,从 Amazon 获得 204。

理想情况下,IETF 会使用 RFC 来解决这个问题,可能会添加一个 HTTP 错误代码来表示“由于表单失效失败而没有执行操作”,或者扩展 422 的定义以涵盖这一点。

于 2016-05-20T21:38:02.983 回答
1

似乎没有一个公认的答案,老实说,这有点令人惊讶。表单验证是 Web 开发的基石,没有响应代码来说明验证失败的事实似乎错失了机会。特别是考虑到自动化测试的普及。通过检查 HTML 内容中的错误消息而不是仅测试响应代码来测试响应似乎不切实际。

我坚持我的断言,即 200 是不符合业务规则的请求的错误响应代码 - 并且 302 也是不合适的。(如果表单验证失败,那么它不应该更新服务器上的任何状态,因此是幂等的,不需要使用 PRG 模式来防止用户重新提交表单。让他们。)

因此,鉴于没有“批准”的方法,我目前正在(字面上)用我自己的测试 - 421。如果我们遇到使用非标准 HTTP 状态代码的任何问题,我会报告回来。

如果这个答案没有更新,那么我们正在生产中使用它,它可以工作,你也可以这样做。

于 2013-03-27T14:41:07.080 回答
-1

如果您不重定向,POST 将返回 200。POST 请求后,302 不会在标头中自动发送,因此您必须手动发送标头(https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpResponse )和代码不依赖表单的数据。

使用代码 302 重定向回表单(或其他)的原因是不允许浏览器在刷新或历史浏览时重复发送数据。

于 2013-03-22T22:51:33.170 回答