Skip to content

🐛 [Bug]: c.Redirect doesn't respect c.Method #3405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
3 tasks done
andradei opened this issue Apr 14, 2025 · 15 comments · May be fixed by #3415
Open
3 tasks done

🐛 [Bug]: c.Redirect doesn't respect c.Method #3405

andradei opened this issue Apr 14, 2025 · 15 comments · May be fixed by #3415

Comments

@andradei
Copy link

andradei commented Apr 14, 2025

Bug Description

Calling c.Method("GET") before c.Redirect("/my/route") doesn't set the method and c.Redirect still uses the method that the handler was originally called with.

How to Reproduce

Steps to reproduce the behavior:

  1. Create route app.Put("/put", putHandler)
  2. Create route app.Get("/get", getHandler)
  3. At the bottom of putHandler have c.Method("GET"); return c.Redirect("/get")
  4. Call /put with "PUT" HTTP method/verb
  5. Notice the redirect is not GET /get but PUT /get despite method being set in item 3 above

Expected Behavior

c.Method("GET") is respected and overrides the method/verb of the original request (PUT, in this example).

Fiber Version

v2.52.6

Code Snippet (optional)

package main

import "github.com/gofiber/fiber/v2"
import "log"

func main() {
  app := fiber.New()
  app.Get("/get", getHandler)
  app.Put("/put", putHandler)

  log.Fatal(app.Listen(":3000"))
}

// This will NEVER be called
func getHandler(c *fiber.Ctx) error {
  c.SendString("")
}

func putHandler(c *fiber.Ctx) error {
  log.Debugf("got here and method it PUT: %v", c.Method())

  c.Method("GET")
  log.Debugf("now the method is set to GET: %v", c.Method())

  // This results in a "PUT /get" request instead of "GET /get"
  c.Redirect("/get")
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my problem prior to opening this one.
  • I understand that improperly formatted bug reports may be closed without explanation.
Copy link

welcome bot commented Apr 14, 2025

Thanks for opening your first issue here! 🎉 Be sure to follow the issue template! If you need help or want to chat with us, join us on Discord https://gofiber.io/discord

@andradei
Copy link
Author

If I make the change below, it works. Is this a bug?

func putHandler(c *fiber.Ctx) error {
  // ...
  c.Redirect("/get", fiber.StatusSeeOther) // <---- this change
}

@ReneWerner87
Copy link
Member

Is this really a bug?
for 307 and 308 the original method must be retained and other redirect status codes also use POST
https://www.webfx.com/web-development/glossary/http-status-codes/what-is-a-307-status-code/
https://www.webfx.com/web-development/glossary/http-status-codes/what-is-a-308-status-code/
so redirect is not only limited to GET

@pjebs
Copy link
Contributor

pjebs commented Apr 14, 2025

What does net/http do?

@ReneWerner87
Copy link
Member

here https://cs.opensource.google/go/go/+/refs/tags/go1.24.2:src/net/http/server.go;l=2416-2425
but still have to check it in the code

@coderabbitai What does net/http do?

Copy link
Contributor

coderabbitai bot commented Apr 14, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Let's look at the Go standard library net/http redirect implementation
curl -s "https://cs.opensource.google/go/go/+/refs/tags/go1.24.2:src/net/http/server.go?q=l%3D2416-2425&ss=go%2Fgo" | grep -A 20 "func Redirect"

# Also let's search for the Fiber redirect implementation
fd -t f -e go . | xargs grep -l "func.*Redirect" | xargs cat | grep -A 30 "func.*Redirect"

Length of output: 30227


🏁 Script executed:

#!/bin/bash
# Let's try to get the Go net/http Redirect implementation more directly
curl -s "https://raw.githubusercontent.com/golang/go/go1.24.2/src/net/http/server.go" | grep -n -A 25 "func Redirect"

Length of output: 2184


🏁 Script executed:

#!/bin/bash
# Let's also check how Fiber sets the default status code for redirects
rg -B 5 -A 3 'func \(r \*Redirect\) release' --type go

Length of output: 324


@ReneWerner87 Looking at Go's standard library (net/http), here's how it handles redirects:

The Redirect function in net/http simply uses whatever status code is passed to it:

func Redirect(w ResponseWriter, r *Request, url string, code int) {
    // Redirect logic here
    // ...
}

Go's net/http doesn't have any default status code for redirects - it uses whatever code is explicitly provided in the function call. It also doesn't perform any special handling for different redirect status codes regarding HTTP method preservation.

In contrast, Fiber defaults to status code 302 (Found) for redirects when no status code is specified:

func (r *Redirect) release() {
    r.status = 302
    r.messages = r.messages[:0]
    r.c = nil
}

This explains the issue - browsers interpret 302 inconsistently. Some preserve the original method (like PUT), while others change to GET. Using 303 (See Other) explicitly tells the browser to use GET for the new request, which is why changing to fiber.StatusSeeOther fixed the issue for the user.

For 307 (Temporary Redirect) and 308 (Permanent Redirect), as you mentioned, browsers must preserve the original HTTP method.

@ReneWerner87
Copy link
Member

@coderabbitai should we change our behavior for the method? would that be better for the consumers? or is the extension of the documentation better for that?

Copy link
Contributor

coderabbitai bot commented Apr 14, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get fiber's Redirect implementation
rg -A 20 -B 5 "func \(c \*Ctx\) Redirect" --type go

# Look for any documentation about redirects in the codebase
rg "Redirect" -A 3 -B 3 --type go | grep -i "// "

# Find where the default redirect status value is set
rg -B 5 -A 3 'status = 302' --type go

Length of output: 9081


🏁 Script executed:

#!/bin/bash
# Let's look at the Ctx.Redirect method implementation
rg -A 40 "func \(c \*Ctx\) Redirect" --type go

# Also examine the redirect.To() method which seems to be the actual implementation
rg -A 25 "func \(r \*Redirect\) To" --type go

# Check how net/http.Redirect is implemented for comparison
curl -s "https://raw.githubusercontent.com/golang/go/go1.24.2/src/net/http/server.go" | grep -n -A 40 "func Redirect"

# Look for info about HTTP redirect status codes in the codebase
rg "302|303|307|308" --type go | grep -i "status"

Length of output: 6402


@ReneWerner87 After analyzing Fiber's redirect implementation, I believe you have two good options:

  1. Change the default behavior:

    • Change default from 302 to 303 (StatusSeeOther) for redirects
    • Benefits: More predictable behavior as 303 always converts to GET across all browsers
    • Drawback: Breaking change for existing applications
  2. Improve documentation:

    • Keep 302 as default but enhance documentation with clear guidance
    • Add examples showing when to use different status codes (303, 307, 308)
    • Highlight that 302 has inconsistent browser behavior

My recommendation is a hybrid approach:

  • Keep 302 as default for backward compatibility
  • Add clear warnings in documentation about 302's inconsistent behavior
  • Create a new configuration option that allows users to change the default redirect status globally
  • Consider adding helper methods like RedirectUsingGet() that uses 303 and RedirectPreservingMethod() that uses 307

This approach preserves backward compatibility while giving developers clear options for specific use cases and better guidance.

@ReneWerner87
Copy link
Member

@coderabbitai does not like helper methods for v2
can you generate the changes for the documentation for v2 and tell us how we could optimize v3 and if the same problem exists there

Copy link
Contributor

coderabbitai bot commented Apr 14, 2025

Tip

For best results, initiate chat on the files or code changes.

A summary of the edits CodeRabbit can apply:

We are going to update the info block in the "To" redirect method (lines 17–19) in the docs/api/redirect.md file to add a note that 302 Found may change the request method. The new text advises users to consider 307 or 308 when preserving the original method is required.

We are going to update the info block for the "Back" redirect method (lines 93–95) in the docs/api/redirect.md file to add a note regarding 302 Found behavior for non‑GET requests.

We are going to insert a new section at the end of the docs/api/redirect.md document (at line 263) outlining future improvements planned for Fiber v3, including a configuration option to set the default redirect status for better method preservation.

We will update the Fiber v2 routing documentation (docs/guide/routing.md) by inserting a "Redirect Behavior" section. This section will explain that the default redirect uses 302 Found, warn users about potential HTTP method alterations (e.g., POST being converted to GET), and advise the use of 307 or 308 when preserving the HTTP method is necessary. It will also outline planned improvements for Fiber v3—suggesting a global configuration option to override the default redirect status—while noting that without explicit configuration, v3 continues to exhibit similar behavior.

We are going to update the FAQ documentation (docs/extra/faq.md) to include a new FAQ entry for v2 that explains the default HTTP redirect behavior and outlines plans for a configurable default in v3.

We are going to update the documentation in

docs/api/redirect_best_practices.md

to clarify the v2 redirection behavior and its caveats, and to outline the proposed improvements for v3 regarding HTTP method preservation during redirects.

A plan of each step that CodeRabbit will take in order to execute the edits for each file (with inline rough draft snippets):

✏️ docs/api/redirect.md :::info If **not** specified, status defaults to **302 Found**.

Note: Using status 302 Found may cause browsers to change the request method from non-GET requests (such as POST or PUT) to GET. If preserving the original method is necessary, consider using 307 Temporary Redirect or 308 Permanent Redirect.
:::

✏️ docs/api/redirect.md :::info If **not** specified, status defaults to **302 Found**.

Note: For redirects involving non-GET requests, 302 may cause the HTTP method to change to GET. To preserve the original method (e.g., for PUT or POST), use 307 Temporary Redirect or 308 Permanent Redirect.
:::

➕ docs/api/redirect.md ## Future Improvements (v3)

In Fiber v3, we plan to introduce a configuration option that allows developers to set the default redirect status code. This option will enable choosing between a method-changing redirect (e.g., 303 See Other) and a method-preserving redirect (e.g., 307 Temporary Redirect or 308 Permanent Redirect).

As of now, both Fiber v2 and the current v3 implementation use 302 Found by default when no status is specified, which may result in a change of HTTP method for non-GET requests. This planned improvement will address the inconsistency and give developers greater control over redirect behavior.

➕ docs/guide/routing.md

Insert a new section with the heading

## Redirect Behavior

at the end of the file.


Add the following documentation content:

## Redirect Behavior

In Fiber v2, the default redirect status code is 302 Found. This means that when a redirect happens, web browsers may change the HTTP method (for example, converting a POST into a GET) depending on the browser implementation. To ensure that the original HTTP method is preserved, especially in scenarios where a non-GET method is required, you should explicitly use one of the following status codes:

  • 307 Temporary Redirect
  • 308 Permanent Redirect

For example, to preserve the HTTP method, use:
c.Redirect("/new-path", fiber.StatusTemporaryRedirect)

For more details, see:

Planned Improvements for Fiber v3:

Fiber v3 is expected to introduce enhanced configurability. A global configuration option may be provided, allowing developers to override the default redirect status code according to their requirements. Without this explicit configuration, the default redirect behavior in v3 might remain similar to that of v2.


Ensure that the new section integrates with the rest of the document's style and formatting. Review the formatted output in preview mode to confirm consistency and readability.

➕ docs/extra/faq.md

Append the following FAQ entry to the end of the file:


## How does Fiber handle HTTP redirects and what should I be aware of?

In Fiber v2, the default redirect behavior uses HTTP status code 302 which does not guarantee method preservation across redirects. This can lead to cases where, for example, a POST or PUT request is converted to a GET request by some browsers. To retain the original HTTP method when redirecting, explicitly use status codes 307 (Temporary Redirect) or 308 (Permanent Redirect):

c.Redirect("/your-url", fiber.StatusTemporaryRedirect)
// or
c.Redirect("/your-url", fiber.StatusPermanentRedirect)

If you require the browser to force a GET on redirect, consider using 303 (See Other):

c.Redirect("/your-url", fiber.StatusSeeOther)

This behavior is consistent with the standard library's net/http package, which uses the provided status code without altering the HTTP method unless explicitly required.

Looking ahead to v3:
While v2 retains 302 as the default for backward compatibility, Fiber v3 is planned to introduce a global configuration option to set the default redirect status code. This enhancement will allow developers to choose a default that better fits their application's needs. Currently, v3 exhibits the same behavior as v2, so explicit status codes should be provided when deviating from the default.

✏️ docs/api/redirect_best_practices.md

Add the following markdown sections at the end of the file.


## Redirect Best Practices in v2

In version 2, the default redirection behavior uses a 302 Found status code. However, please note the following points:

  • A 302 redirect may result in browsers changing the HTTP method (for example, converting a POST or PUT into a GET) due to inconsistent browser implementations.
  • To explicitly enforce a GET method upon redirection, use fiber.StatusSeeOther (303).
  • To preserve the original HTTP method (critical for PUT or POST requests), specify 307 (Temporary Redirect) or 308 (Permanent Redirect).

Recommendation for v2:
Always explicitly specify the desired redirect status code in your calls to the redirect function rather than relying on the default 302. This proactive approach avoids unexpected behavior across different clients.


Future Optimizations in v3

For version 3, we propose the following optimizations to further improve redirect handling:

  • Global Configuration Option: Introduce a configuration setting to allow developers to define the default redirect status code globally. This would enable safer defaults without breaking existing applications.
  • Safer Default Behavior: Consider defaulting to 303 (See Other) for scenarios where redirection should enforce a GET method, thereby reducing unintended side effects.
  • Enhanced Guidelines: Update the documentation with a detailed comparison of the redirect status codes (302, 303, 307, and 308), including how they impact HTTP method retention.
  • Backward Compatibility: Maintain the existing default of 302 in v2 but strongly recommend explicit status code usage, while planning for a smoother transition in v3.

Does the same problem exist in v3?
Yes, the issue with HTTP method changes during redirects persists if the status code is not chosen carefully. The planned v3 improvements are aimed at mitigating these inconsistencies, providing developers with clearer options and safer defaults.


Review the updated sections and ensure that any related guidelines in the documentation index are updated accordingly.

A summary of the context that CodeRabbit is considering across the codebase:

This change clarifies that the default 302 status code may not be ideal for non‐GET requests by explicitly noting that the HTTP method might be altered. This information, corroborated by our web search results on the behavioral differences between HTTP status codes, ensures users are better informed when choosing a redirect status.

This update mirrors the note added in the "To" method section to help users understand that the default behavior of 302 might lead to an unexpected HTTP method change when handling non‑GET requests. This guidance is based on our web search analysis regarding browser behavior with HTTP 302 redirects.

The insertion of this section informs developers about upcoming changes for Fiber v3. It clarifies that while the current behavior (using 302 Found by default) persists, future versions will offer a configuration option to choose a default status code that better preserves the HTTP method as needed.

Our investigation revealed that Fiber’s default redirect behavior in v2 uses HTTP 302, which may convert POST/PUT requests to GET in some browsers. This behavior contrasts with the explicit use of status codes 307/308, which preserve the original method. While Fiber v2 continues to default to 302 for backward compatibility, our analysis suggests that updating the FAQ documentation is the best approach for v2. In the upcoming Fiber v3, a global configuration option to set the default redirect status code is planned to optimize this behavior. This change will enable users to more clearly choose between preserving HTTP methods (using 307/308) or forcing GET (using 303) on redirects.

  • ✅ Create PR with these edits

  • 📋 Get copyable edits

  • 🔄 Try a different approach

@andradei
Copy link
Author

Changing default to 303 (at least on v3) and adding warnings in the docs about the 302 default is a satisfactory solution, I think.
Changing the default to 303 to v2 would be ideal, however.

@andradei
Copy link
Author

andradei commented Apr 14, 2025

@ReneWerner87 I can work on this.
For v2, it would be a breaking change. If you don't want to potentially break v2 users, I can add the docs on v2 and change the default on v3.

@ReneWerner87
Copy link
Member

@ReneWerner87 I can work on this. For v2, it would be a breaking change. If you don't want to potentially break v2 users, I can add the docs on v2 and change the default on v3.

Would be nice
Pls, no breaking change for v2

V2: docs update
V3: changing the default

andradei added a commit to andradei/fiber that referenced this issue Apr 18, 2025
Closes gofiber#3405

In some browsers, redirect status 302 Found sometimes is used to change
the HTTP verb of the response from what the user set to what was used in
the request. Changing to 303 SeeOther in the default works more like
expected: it defaults to GET and can be overriden by the user.
@andradei andradei linked a pull request Apr 19, 2025 that will close this issue
andradei added a commit to andradei/fiber that referenced this issue Apr 19, 2025
@andradei
Copy link
Author

Two PRs created:

@gaby
Copy link
Member

gaby commented Apr 22, 2025

I'm confused as to why we are changing all the places from 302 to 303?

They are very different things, see https://en.m.wikipedia.org/wiki/HTTP_302

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants