DEV BOX

'26/09/27 UPDATE

WEB / FIELD NOTES

Why the request after a POST redirect is sometimes a GET

A fictional POST /orders followed after 301 or 302 becomes a GET with no body. 303 makes that change on purpose. 307 and 308 keep the method.

The order URL is https://shop.example/orders. The method is POST, Content-Type is application/json, and the body is {"sku":"MUG-1","qty":1}. If the response is 302 and Location is https://shop.example/orders/1001, a browser that follows that URL sends the next request as a GET with no body. The same Location with 307 keeps the next request as POST. shop.example, MUG-1, and quantity 1 are fictional. The explanation comes from the standards. The same four cases were later run on local servers in a Chromium 152 browser on September 27, 2026, and that log is at the end.

The boundary is RFC 9110 and the Fetch standard as read on 2026-09-26. RFC 9110 says what a user agent may change. Fetch states the steps a browser follows when the redirect mode is follow. Unless set otherwise, that mode is follow. A client that does not implement Fetch, such as curl, can keep the method for the same status code.

Permanent, temporary, and the method are different questions

301 Moved Permanently means the target resource has a new permanent URI, and later references ought to use it. 308 Permanent Redirect is also permanent. 302 Found and 307 Temporary Redirect mean the resource is elsewhere for now, so later requests ought to keep using the original URI.

301 and 302 carry a historical exception. A user agent may change the next method from POST to GET. When that change is not wanted, use 308 for a permanent move and 307 for a temporary one. 307 and 308 must not change the method on an automatic redirect.

303 See Other is not a notice that the same resource has moved. The Location URI is not equivalent to the original target, and a user agent can retrieve it with GET or HEAD. The usual purpose is to point at the result of a POST, at an address that can be bookmarked and cached.

301 and 308 are on the heuristic cache list. 302, 303, and 307 are not. A status outside that list can still be stored when freshness is explicit, as with Cache-Control. A POST response follows the method rule first. It is cacheable only with explicit freshness and a Content-Location equal to the POST URI, and even then a stored response can satisfy a later GET or HEAD. A 301 does not by itself store the POST response.

DEV NOTES

Permanent, temporary, and method are separate

RFC 9110 · checked 2026-09-26 · no sample URL

  • 301 Moved Permanently

    301

    • A new permanent URI for later references
    • POST may be changed to GET
    • On the heuristic cache list
  • 302 Found

    302

    • Temporarily elsewhere. Keep the original URI
    • POST may be changed to GET
    • Not on the heuristic cache list
  • 303 See Other

    303

    • A different resource, not equivalent
    • Follow it with GET or HEAD
    • Used to show the result of a POST
  • 307 and 308

    307 / 308

    • 307 is temporary, 308 is permanent
    • Automatic follow keeps the method
    • Only 308 is on the heuristic cache list

301 and 308 are heuristically cacheable, but a POST response follows the method rule. It is cacheable only with explicit freshness and a Content-Location equal to the POST URI.

Permanent or temporary, whether the method changes, and the heuristic cache list are three separate questions.

When a browser follows, a 302 POST becomes GET

With follow, Location is resolved against the URL of the request that received the response, then requested again. error is a network error. manual does not follow unless the request is a navigation. An automatic redirect of a method that is not safe needs care, but the fetch default is still follow.

When the status is 301 or 302 and the method is POST, Fetch sets the method to GET and the body to null. Following the 302 above produces GET https://shop.example/orders/1001 with no body. The product code and quantity are not on that request.

The same Location on 307 or 308 does not enter that condition. The method stays POST, and the body is attached again when it can be reread. Fetch follow applies the change RFC 9110 allows for 301 and 302. That allowance is not a requirement for every client.

DEV NOTES

The same POST, after 302 and after 307

Fictional · Fetch follow · not executed

  • First request

    POST

    • POST https://shop.example/orders
    • Content-Type: application/json
    • Body {"sku":"MUG-1","qty":1}
  • 302 Location /orders/1001

    GET

    • Next method is GET
    • Body is null
    • Content-Type is removed
  • 307 keeps the method

    POST

    • Same Location
    • Method stays POST
    • The body is sent again if it can be reread

shop.example, MUG-1, and quantity 1 are fictional. RFC 9110 allows a user agent to change POST to GET for 301 and 302. Fetch follow applies that change.

The same fictional order does not make the same next request after 302 and after 307.

303 is the GET that shows the result

303 is not limited to POST. If the method is neither GET nor HEAD, Fetch sets it to GET and drops the body. A PUT or DELETE followed on 303 is also a GET.

301 and 302 are narrower. Fetch changes only POST to GET for those two codes. A fictional PUT https://shop.example/orders/1001 that receives 302 to another URL stays PUT under follow.

A 303 Location is not the same place as the original resource. After a POST that creates an order, a 303 to /orders/1001 points at the result, and opening that page again does not repeat the POST. A 302 can produce a similar method change, but it is not defined as showing a different resource.

DEV NOTES

303 is a GET that shows the result

Fictional · same order URL · not executed

  • 303 after the POST

    303

    • Location https://shop.example/orders/1001
    • Not equivalent to the original URI
    • Next request is a GET with no body
  • 302 has a different role

    • 302 means the same resource is elsewhere for now
    • Changing POST to GET is a historical allowance
    • A 303 GET is defined as retrieving another resource
  • PUT stays on a 301

    PUT

    • Fetch changes only POST to GET for 301 and 302
    • A fictional PUT /orders/1001 stays PUT after 302
    • 303 turns PUT and DELETE into GET as well

Use 303 when a refresh should not repeat the POST. A 302 can change the method, but it does not mean the next URI is a different resource.

Use 303 to show the result. Use 307 or 308 to keep the POST.

What remains of the headers and the body

When the method becomes GET or HEAD, Fetch removes Content-Encoding, Content-Language, Content-Location, and Content-Type. RFC 9110 also says to remove content-specific fields such as Content-Length and Digest. The two lists of names are not the same. In this fictional example, Content-Type application/json is removed.

A change of origin also removes Authorization. Going from https://shop.example to https://pay.example drops that name at this step. A same-origin /orders/1001 does not remove Authorization here. Cookies can be attached later according to the credentials mode, so they are not treated like Authorization. The separate case of a cross-origin JSON request being blocked is covered in Why a CORS error can mean the server never saw the POST.

If the status is not 303, the body is present, and that body cannot be reread, Fetch returns a network error. Following a 307 with a stream that can be read only once can fail. 303 drops the body, so it skips that check. The redirect count starts at zero, and the redirect after 20 followed responses is a network error. An older recommendation was a maximum of five, and some clients may still use a fixed limit. A Location that is not http or https is not followed.

DEV NOTES

What a follow drops, and what stops it

Fetch HTTP-redirect fetch · checked 2026-09-26

  • Names removed when it becomes GET

    Fetch

    • Content-Encoding
    • Content-Language, Content-Location
    • Content-Type
  • When the origin changes

    • From shop.example to pay.example
    • This step removes only Authorization
    • Same origin keeps Authorization
  • A body that cannot be reread fails

    20

    • Except for 303, the body source must exist
    • A one-shot stream on 307 can fail
    • After 20 follows, the next redirect fails

RFC 9110 also says to drop Content-Length and Digest when the method becomes GET or HEAD. Fetch removes the four body-header names above. This article did not re-run the steps in a browser.

A new method drops the body headers. A new origin drops Authorization.

Do not choose the next request from the status alone

On a log, write down the first status and Location, the second method and whether it had a body, and the origins of the two URLs. A second request that is GET does not by itself mean the server rejected the POST. These branches are the procedure in the standards. Sending the same requests to local servers instead of the fictional URL produced a log that matches them.

Local server log. After POST /orders?status=302 comes GET /orders/1001, after 303 also GET, after 307 a POST /orders/1001 with the JSON body, and the 302 to another origin is followed by a GET without Authorization.
The fictional order (MUG-1, quantity 1) moved to local servers and sent through 302, 303, 307, and a 302 to another origin. The server log matches the rules in the text.
THE END
RSS feedBack to the library
COMMENTS BOX

Add your perspective.

Share a question, another approach, or something you have tried.

Newest first

Checking sign-in…

Loading comments…