How to redirect HTTP put, post or delete requests and why you may end up with a GET request upon redirection

I will start with a small disclaimer: it is always up to the client how to handle redirects. Most of the time they handle status codes according to the spec, but browsers can handle redirects differently and it gets worse the further your browser support goes back. With that in mind, let us jump right into it.

Redirection

The most common ways to redirect are the following:

  • 301 Moved Permanently
  • 302 Found
  • 303 See Other
  • 307 Temporary Redirect
  • 308 Permanent Redirect (experimental)

There are other codes in the 300 redirect space, such as 304 (Not Modified), but this is a "redirect" to use the cache in your browser and is not interesting for this blog post.

The short version: 301 and 302 do not necessarily make the exact same request for the resource redirected to, which means that a put/post/delete may be turned into a get, but 307 and 308 should keep the HTTP verb and body. So if you are using 301/302 and are having trouble redirecting put, post or delete requests try with a 307 or 308 response code. The difference between 308 and 301 according to the specification is that the 308 must make the exact same request and not change the HTTP verb. Both 301 and 308 are permanent redirects, which means all future requests will be done directly to the new resource. This can cause you trouble as clients heavily cache this (as they should), so if you redirect to the wrong resource the client will not request the initial resource again but be stuck requesting the new but wrong resource.

302 and 307 are temporary redirects, this means that the client should not cache the redirect and should request the original resource next time as it has only been moved temporarily. Just as with the 301 and 308 redirects, 302 may not keep the HTTP verb, but 307 should according to the RFC7231 specification. So a 307 redirect on a PUT request should redirect to a PUT request for example. It it specifically stated in the RFC that "the user agent MUST NOT change the request method if it performs an automatic redirection to that URI" for responses with 307 status code.

Wikipedia states that the 302 was sometimes implemented as a 303 (see other) in the industry, the 303 redirect is defined on Wikipedia as: "The response to the request can be found under another URI using the GET method. When received in response to a POST (or PUT/DELETE), the client should presume that the server has received the data and should issue a new GET request to the given URI." This means that the initial put/post/delete was handled and you should now get the resource on the redirection URL. So the browser always uses a get on the URL given in the redirect. 303 can be used on a put/post/delete where you actually want the browser to get the resource at the redirected URL. This can be used if your request is not necessarily processed right away, but you redirect the user to the loading page.

Browser support

As previously mentioned it is up to the client how it handles redirects. According to Monty on Stackoverflow the support for 307 and 308 is the following:

  • Fail - IE 11 (Version 11.0.9600.18893) on Windows 7. On using a 308 in a site, the browser just appears to hang and not load anything. [Edit] As of 25 July 2018, this is still failing (Version 11.0.9600.19035) - checked just in case, you know, MS decided to do the world of devs a favour.
  • Pass - IE 11 (Version 11.786.15063.0) on Windows 10
  • Pass - Edge (Version 40.15063.674.0) on Windows 10
  • Pass - Chrome (Versions 63.0.3239.132 and 63.0.32.132) on Windows 7 and Mac OS 11.6 respectively
  • Pass - Opera (Version 50.0.2762.67) on Mac OS 11.6
  • Pass - Firefox (Versions 54.0.4 and 47.0.2) on Mac OS 11.6 and Windows 7 respectively
  • Pass - Safari (Version 11.0.3) on Mac OS 11.6

Which means that all modern browsers support this. Microsoft ended Windows 7 support on January the 20th 2020, so over time the amount of Internet explorer eleven (IE11) users should drop. Currently IE11 is accounting for 1.75% of the browser traffic according to w3counter.

In short:

  • 301 - Redirects permanently and may not make the exact same request on the redirected resource
  • 302 - Redirects temporarily and may not make the exact same request on the redirected resource
  • 307 - Redirects temporarily and should make the exact same request on the redirected resource
  • 308 - Redirects permanently and should make the exact same request on the redirected resource

I have written should, as browsers have their own implementations, at first I had written will. Using 307 and 308 will likely give you the result that you would expect, except when it comes to older browsers.

I hope this post helped you, if it did or did not, please let me know in the comments down below!

Resources: