There are some similar status codes in HTTP status codes, which can be confusing. The less popular ones are 405(Method Not Allowed) and 501(Not Implemented). Isn’t a request not implemented if the requested method is not supported? What’s the difference between the two? Let’s take a closer look at it.

Definition of status code

The most authoritative definition of a status code is the RFC-2616 document:

6.5.5. 405 Method Not Allowed The 405 (Method Not Allowed) status code indicates that the method received in the request-line is known by the origin server but not supported by the target resource. The origin server MUST generate an Allow header field in a 405 response containing a list of the target resource’s currently supported methods.

The 405 status code represents the method in the request (recall that the HTTP request line consists of three parts, the request method, the request resource, and the request version number, for example: GET /some/amazing/resource HTTP/1.1) the target server knows about the requested resource, but the server cannot respond with the requested method. At the same time, the protocol requires that the response header must contain the Allow header, which returns the request method that supports the corresponding resource.

The 501 Not Implemented The 501 (Not Implemented) status code indicates that The server does Not support The functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.

The 501 status code indicates that the destination server does not know the method you requested and is unable to respond to all requested resources.

To compare

There’s a subtle difference.

405

The request methods (GET, PUT, DELETE) are recognized by the API server, but for the resource (URI) you request, the method you use is not supported by the API Server. This is called method disallow.

For example, if lifecycle requests are made to AWS S3 objects, this type of resource only supports GET, PUT, and DELETE methods. If lifecycle requests are made to AWS S3 objects with a HEAD method, lifecycle requests will return the following error:

Curl - VVV-I "https://s3-ap-southeast-1.amazonaws.com/test-voidmain-method/?lifecycle" * Trying 52.219.40.137... * TCP_NODELAY set * Connected to S3-AP-southecommencement 1.Amazonaws.com (52.219.40.137) Port 443 (#0) * TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * Server certificate: *.s3-ap-southeast-1.amazonaws.com * Server certificate: DigiCert Baltimore CA-2 G2 * Server certificate: Baltimore CyberTrust Root > HEAD /test-voidmain-method/? Lifecycle HTTP/1.1 > Host: S3-ap-southeast-1.amazonaws.com > ACCEPTANCE: */* > < HTTP/1.1 405 Method Not Allowed HTTP/1.1 405 Method Not Allowed < X-AMz-request-id: 5ECA8F9A66AC236B x-amz-request-id: 5ECA8F9A66AC236B < x-amz-id-2: mM6O8oq7yytIjjg+CtB94SN09CZjZE975f1cIhLPzRlFmJEYclANCVxnzgyoAMdd3SBsm2uqBnQ= x-amz-id-2: mM6O8oq7yytIjjg+CtB94SN09CZjZE975f1cIhLPzRlFmJEYclANCVxnzgyoAMdd3SBsm2uqBnQ= < Allow: DELETE, GET, PUT Allow: DELETE, GET, PUT < Content-Type: application/xml Content-Type: application/xml < Transfer-Encoding: chunked Transfer-Encoding: chunked < Date: Sat, 30 Sep 2017 03:31:57 GMT Date: Sat, 30 Sep 2017 03:31:57 GMT < Server: AmazonS3 Server: AmazonS3 < * Connection #0 to host s3-ap-southeast-1.amazonaws.com left intactCopy the code

In particular, the Allow header in the response header returns the GET, PUT, and DELETE methods, which are all HTTP methods supported by this resource.

501

501 means that your request method (such as PROPFIND method) is not recognized by API Server and is therefore unimplemented. Returning 501 is largely restricted to the API Server implementation. The jetty version used by the company only supports the request method defined in RFC-2068, so a request using the PROPFIND method returns 501. For example :(specific domain names, ports and IP addresses are hidden for privacy reasons)

curl -vvv -X PROPFIND "http://example.com" * Rebuilt URL to: http://example.com/ * Trying xx.xx.xx.xx... * TCP_NODELAY set * Connected to example.com (xx.xx.xx.xx) port 80 (#0) > ASDFASDF/HTTP/1.1 > Host: Example.com > user-agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 501 Method PROPFIND is not defined in RFC 2068 and is not supported by the Servlet API < Server: XXX < Date: Sat, 30 Sep 2017 03:12:55 GMT < Content-Length: 0 < Connection: keep-alive < X-Application-Context: application < * Connection #0 to host example.com left intactCopy the code

This action is done by Jetty:

10:51:05.498 415559652 [6061] [qtp2047899112-1676226 - /] DEBUG O.E.jetty.server.Server REQUEST PROPFIND/on HttpChannelOverHttp@55741056{r=1, C =false, A =DISPATCHED, URI =/} 10:51:05.499 415559653 [6061] [QTP2047899112-1676226 - /] DEBUG o.e.j.s.h.ContextHandler scope null||/ @ o.s.b.c.e.j.JettyEmbeddedWebAppContext@4d56b779{/,null,AVAILABLE} 10:51:05. 499, 415559653 [6061] [qtp2047899112-1676226 - /] the DEBUG O.E.J.S.H.C ontextHandler context = | | / @ 4 d56b779 O.S.B.C.E.J.J ettyEmbeddedWebAppContext @ {/, null, the AVAILABLE} 10:51:05. 499, 415559653 [6061] [qtp2047899112-1676226 -  /] DEBUG o.e.jetty.server.session sessionManager=org.eclipse.jetty.server.session.HashSessionManager@6011c7cf 10:51:05.499 415559653 [6061] [qTP2047899112-1676226 - /] DEBUG O.E.jetty.server. session Session = NULL 10:51:05.499 415559653 [6061] [qtp2047899112-1676226 - /] DEBUG o.e.j.s.ServletHandler servlet ||/ -> DispatcherServlet @ 7 ef5559e = = org. Springframework. Web. Servlet. The dispatcherServlet, 1, true 10:51:05. 499, 415559653 [6061] [qtp2047899112-1676226 - /] DEBUG o.e.j.s.ServletHandler chain=apiFilter->applicationContextIdFilter->webRequestLoggingFilter->dispatcherServlet@7ef5559e==org.springframework.we B.s ervlet DispatcherServlet, 1, true 10:51:05. J, 499, 415559653 [6061] [qtp2047899112-1676226 - /] the DEBUG O.E.J.S. Servlethandler Call Filter apiFilter 10:51:05.499 415559653 [6061] [QTP2047899112-1676226 - /] DEBUG O.E.J.S.S ervletHandler call filter applicationContextIdFilter 10:51:05. 499, 415559653 [6061] [qtp2047899112-1676226 - /] DEBUG O.E.J.S. Servlethandler Call Filter webRequestLoggingFilter 10:51:05.499 415559653 [6061] [qTP2047899112-1676226 - /] DEBUG o.e.j.s.ServletHandler call servlet DispatcherServlet @ 7 ef5559e = = org. Springframework. Web. Servlet. The dispatcherServlet, 1, true 10:51:05. 499, 415559653 [6061] [qtp2047899112-1676226 - /] DEBUG o.e.j.s.HttpConnection Org. Eclipse. Jetty. Server. HttpConnection $SendCallback @ 4521 a8a2 [PROCESSING] [I = ResponseInfo {HTTP / 1.0 501 Method PROPFIND is  not defined in RFC 2068 and is not supported by the Servlet API ,-1,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback@24c64723] generate: NEED_HEADER (null,[p=0, L =0, C =0,r=0],true) @start 10:51:05.499 415559653 [6061] [qTP2047899112-1676226 - /] DEBUG O.E.J.S.H ttpConnection org. Eclipse. Jetty. Server. HttpConnection $SendCallback @ 4521 a8a2 [PROCESSING] [I = ResponseInfo {HTTP / 1.0  501 Method PROPFIND is not defined in RFC 2068 and is not supported by the Servlet API ,-1,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback@24c64723] generate: FLUSH ([p=0,l=227,c=8192,r=227],[p=0,l=0,c=0,r=0],true)@COMPLETINGCopy the code

But AWS is not implemented that way :(AWS returns 400)

Curl - VVV-x ROPFAS "https://s3-ap-southeast-1.amazonaws.com/test-voidmain-method" * Trying 52.219.32.101... * TCP_NODELAY set * Connected to S3-AP-southecommencement 1.Amazonaws.com (52.219.32.101) port 443 (#0) * TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * Server certificate: *.s3-ap-southeast-1.amazonaws.com * Server certificate: DigiCert Baltimore CA-2 G2 * Server certificate: Baltimore CyberTrust Root > ROPFAS /test-voidmain method HTTP/1.1 > Host: S3-AP-southeast-1.Amazonaws.com > User-agent: Curl /7.54.0 > < HTTP/1.1 400 Bad Request < Date: Sat, 30 Sep 17 03:20:19 GMT < Connection: close < Transfer-Encoding: chunked < x-amz-id-2: KMMj8crIsT1SPVKbK5sVnuxbqkNSMbzq4XHVAfIA9V6BUuzYIR7AX5XXeInRgJg9tlnaE9wO2ba0SvIIB/VSebPu87jR9Q5o < x-amz-request-id: 69FAB6DEE37AC9B9 < Content-Type: Application/XML < * Closing connection 0 <? XML version="1.0" encoding="UTF-8"?><Error><Code>BadRequest</Code><Message>An  error occurred when parsing the HTTP request.</Message><RequestId>69FAB6DEE37AC9B9</RequestId><HostId>KMMj8crIsT1SPVKbK5sVnuxbqkNSMbzq4XHVAfIA9V6BUuzYIR7AX5X XeInRgJg9tlnaE9wO2ba0SvIIB/VSebPu87jR9Q5o</HostId></Error>Copy the code

Another point worth discussing is what is returned if we access the API with a request method that Jetty recognizes (defined in RFC-2068) but is not supported by the API (no registered requestMapper) :

curl -vvv -X PATCH "http://example.com/12345/?lifecycle" * Trying xx.xx.xx.xx... * TCP_NODELAY set * Connected to example.com (xx.xx.xx.xx) port 80 (#0) > PATCH /12345/? Lifecycle HTTP/1.1 > Host: Example.com > user-agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 405 Request method 'PATCH' not supported < Server: XXX < Date: Sat, 30 Sep 2017 03:26:03 GMT < Content-Length: 0 < Connection: keep-alive < X-Application-Context: application < Allow: DELETE, GET, PUT, HEAD, OPTIONS, POST < * Connection #0 to host example.com left intactCopy the code

But this return is not standard because THE resource I requested is Lifecycle and Lifecycle does not support POST, OPTIONS, etc. The reason is that this 405 is also returned by Jetty, and Jetty can’t understand the business resource type, so it returns all the request types we support.

Looking at the log will confirm that this action is Jetty’s:

10:49:03.228 415437382 [6061] [qTP2047899112-1676226 - /] DEBUG O.E.jetty.server.Server REQUEST PATCH/on HttpChannelOverHttp@462350f6{r=1, C =false,a=DISPATCHED, URI =/} 10:49:03.228 415437382 [6061] [qTP2047899112-1676226 - /] DEBUG o.e.j.s.h.ContextHandler scope null||/ @ o.s.b.c.e.j.JettyEmbeddedWebAppContext@4d56b779{/,null,AVAILABLE} 10:49:03. 228, 415437382 [6061] [qtp2047899112-1676226 - /] the DEBUG O.E.J.S.H.C ontextHandler context = | | / @ 4 d56b779 O.S.B.C.E.J.J ettyEmbeddedWebAppContext @ {/, null, the AVAILABLE} 10:49:03. 228, 415437382 [6061] [qtp2047899112-1676226 -  /] DEBUG o.e.jetty.server.session sessionManager=org.eclipse.jetty.server.session.HashSessionManager@6011c7cf 10:49:03.228 415437382 [6061] [qTP2047899112-1676226 - /] DEBUG O.E.jetty.server. session Session = NULL 10:49:03.228 415437382 [6061] [qtp2047899112-1676226 - /] DEBUG o.e.j.s.ServletHandler servlet ||/ -> DispatcherServlet @ 7 ef5559e = = org. Springframework. Web. Servlet. The dispatcherServlet, 1, true 10:49:03. 228, 415437382 [6061] [qtp2047899112-1676226 - /] DEBUG o.e.j.s.ServletHandler chain=apiFilter->applicationContextIdFilter->webRequestLoggingFilter->dispatcherServlet@7ef5559e==org.springframework.we B.s ervlet DispatcherServlet, 1, true 10:49:03. J, 228, 415437382 [6061] [qtp2047899112-1676226 - /] the DEBUG O.E.J.S. Servlethandler Call Filter apiFilter 10:49:03.228 415437382 [6061] [qTP2047899112-1676226 - /] DEBUG O.E.J.S.S ervletHandler call filter applicationContextIdFilter 10:49:03. 228, 415437382 [6061] [qtp2047899112-1676226 - /] DEBUG O.E.J.S. Servlethandler Call Filter webRequestLoggingFilter 10:49:03.228 415437382 [6061] [qTP2047899112-1676226 - /] DEBUG o.e.j.s.ServletHandler call servlet DispatcherServlet @ 7 ef5559e = = org. Springframework. Web. Servlet. The dispatcherServlet, 1, true 10:49:03. 228, 415437382 [6061] [qtp2047899112-1676226 - /] DEBUG o.s.w.s.DispatcherServlet DispatcherServlet with name 'dispatcherServlet' processing PATCH request for [/] 10:49:03. 228, 415437382 [6061] [qtp2047899112-1676226 - /] the DEBUG O.S.B.A.E.M.E ndpointHandlerMapping Looking up handler method for Path / 10:49:03.228 415437382 [6061] [qtp2047899112-1676226 - /] DEBUG O.S.B.A.E.M.E ndpointHandlerMapping Did not find a handler method for [/] 10:49:03. 228, 415437382 [6061] [qtp2047899112-1676226 - /] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping Looking up handler method for path /ExceptionHandlerExceptionResolver Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request Method 'PATCH' Not supported 10:49:03.229 415437383 [6061] [qtp2047899112-1676226 - /] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'PATCH' not supportedCopy the code

Combining the above experiments, we can see that Jetty handles the distinction between 405 and 501 by: the method defined in RFC-2068 returns 405 if the requested URL does not match, and returns all the request methods defined in the API. If the requested method is not defined in RFC-2068, return 501 directly.

How to use 405 and 501?

So how do app developers use both?

Analysis down, the most reasonable way to deal with is, if the request method and request resources can match, and can be processed normally, then go to the normal logic; If the match is not successful, the system first parses the resources required by the request, searches for request methods that support the resource based on the resources, and concatenates these methods into the Allow header and returns them to the client. If no method can be found based on the resource, return 501.

In addition, it should be noted that HTTP status code 5xx is generally considered to be a server error, so the company’s monitoring system may monitor all 5XX requests, so 501 May affect the monitoring alarm, which needs to be paid attention to. If the implementation is reasonable, you can ignore the 501 status code in the monitoring.