Should I use HTTP 4xx to indicate HTML form errors

2019-01-28 00:34发布

问题:

I just spent 20 minutes debugging some (django) unit tests. I was testing a view POST, and I was expecting a 302 return code, after which I asserted a bunch database entities were as expected. Turns out a recently merged commit had added a new form field, and my tests were failing because I wasn't including the correct form data.

The problem is that the tests were failing because the HTTP return code was 200, not 302, and I could only work out the problem by printing out the response HTTP and looking through it. Aside from the irritation of having to look through HTML to work out the problem, a 200 seems like the wrong code for a POST that doesn't get processed. A 4xx (client error) seems more appropriate. In addition, it would have made debugging the test a cinch, as the response code would have pointed me straight at the problem.

I've read about using 422 (Unprocessable Entity) as a possible return code within REST APIs, but can't find any evidence of using it within HTML views / handlers.

My question is - is anyone else doing this, and if not, why not?

[UPDATE 1]

Just to clarify, this question relates to HTML forms, and not an API.

It is also a question about HTTP response codes per se - not Django. That just happens to be what I'm using. I have removed the django tag.

[UPDATE 2]

Some further clarification, with W3C references (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html):

10.2 Successful 2xx

This class of status code indicates that the client's request was successfully received, understood, and accepted.

10.4 Client Error 4xx

The 4xx class of status code is intended for cases in which the client seems to have erred.

10.4.1 400 Bad Request

The request could not be understood by the server due to malformed syntax.

And from https://tools.ietf.org/html/rfc4918#page-78

11.2. 422 Unprocessable Entity

The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

[UPDATE 3]

Digging in to it, 422 is a WebDAV extension[1], which may explain its obscurity. That said, since Twitter use 420 for their own purposes, I think I'll just whatever I want. But it will begin with a 4.

[UPDATE 4]

Notes on the use of custom response codes, and how they should be treated (if unrecognised), from HTTP 1.1 specification (http://tools.ietf.org/html/rfc2616#section-6.1.1):

HTTP status codes are extensible. HTTP applications are not required to understand the meaning of all registered status codes, though such understanding is obviously desirable. However, applications MUST understand the class of any status code, as indicated by the first digit, and treat any unrecognized response as being equivalent to the x00 status code of that class, with the exception that an unrecognized response MUST NOT be cached. For example, if an unrecognized status code of 431 is received by the client, it can safely assume that there was something wrong with its request and treat the response as if it had received a 400 status code. In such cases, user agents SHOULD present to the user the entity returned with the response, since that entity is likely to include human- readable information which will explain the unusual status.

[1] https://tools.ietf.org/html/rfc4918

回答1:

You are right that 200 is wrong if the outcome is not success.

I'd also argue that a success-with-redirect-to-result-page should be 303, not 302.

4xx is correct for client error. 422 seems right to me. In any case, don't invent new 4xx codes without registering them through IANA.



回答2:

There doesn't appear to be an accepted answer, which to be honest, is a bit surprising. Form validation is such a cornerstone of web development that the fact that there is no response code to illustrate a validation failure seems like a missed opportunity. Particularly given the proliferation of automated testing. It doesn't seem practical to test the response by examining the HTML content for an error message rather than just testing the response code.

I stick by my assertion in the question that 200 is the wrong response code for a request that fails business rules - and that 302 is also inappropriate. (If a form fails validation, then it should not have updated any state on the server, is therefore idempotent, and there is no need to use the PRG pattern to prevent users from resubmitting the form. Let them.)

So, given that there isn't an 'approved' method, I'm currently testing (literally) with my own - 421. I will report back if we run into any issues with using non-standard HTTP status codes.

If there are no updates to this answer, then we're using it in production, it works, and you could do the same.



回答3:

It's obvious that some form POST requests should result in a 4xx HTTP error (e.g. wrong URL, lacking an expected field, failing to send an auth cookie), but mistyping passwords or accidentally omitting required fields are extremely common and expected occurrences in an application.

It doesn't seem clear from any spec that every form invalidation problem must constitute an HTTP error.

I guess my intuition is that, if a server sends a client a form, and the client promptly replies with a correctly-formed POST request to that form with all expected fields, a common business logic violation shouldn't be an HTTP error.

The situation seems even less defined if a client-side script is using HTTP as a transport mechanism. E.g. if a JSON-RPC requests sends form details, the server-side function is successfully called and the response returned to the caller, seems like a 200 success.

Anecdotally: Logging in with bad credentials yields a 200 from Facebook, Google, and Wikipedia, and a 204 from Amazon.

Ideally the IETF would clear this up with an RFC, maybe adding an HTTP error code for "the operation was not performed due to a form invalidation failure" or expanding the definition of 422 to cover this.



回答4:

The POST returns 200 if you do not redirect. The 302 is not sent automatically in headers after POST request, so you have to send the header (https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpResponse) manually and the code does not relay on data of the form.

The reason of the redirection back to the form (or whatever) with code 302 is to disallow browser to send the data repeatedly on refresh or history browsing.



标签: http