flask: Automatic redirect with "/" breaks routes with different methods

I have found an issue that is caused by the automatic redirect of routes to the version with a “/” at the end. See the code below for a minimal example:

from flask import Flask
app = Flask(__name__)


@app.route("/a/", methods=["GET"])
def hello():
    return "Hello GET!\n"


@app.route("/a", methods=["POST"])
def hello_post():
    return "Hello POST!\n"

if __name__ == "__main__":
    app.run()

The POST route is unreachable as the “/” redirect is done without looking at the method. See the following curl commands (the -L flag is to follow redirects):

$ curl localhost:5000/a/
Hello GET!

$ curl localhost:5000/a
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="http://localhost:5000/a/">http://localhost:5000/a/</a>.  If not click the link.

$ curl localhost:5000/a -L
Hello GET!

$ curl localhost:5000/a -X POST
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="http://localhost:5000/a/">http://localhost:5000/a/</a>.  If not click the link.

$ curl localhost:5000/a/ -X POST
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>

$ curl localhost:5000/a -X POST -L
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>

Edit: My python version is Python3.4 and Werkzeug is 0.11.8 but it was also possible with the git version of Werkzeug.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 20 (12 by maintainers)

Most upvoted comments

Hello @JelteF Really, your method of doing this is bad practice. I’ll show you a method that will solve this issue for you.

from flask import Flask, request

app = Flask(__name__)


@app.route("/hello", methods=["GET", "POST"])
def hello():
    if request.method == "POST":
        return "Hello POST!"
    return "Hello GET!"


if __name__ == '__main__':
    app.run()

I always put both get and post in to one method. It’s best practice and it keeps your code really clean and easy to read.

Pretty ugly IMO (not to mention that camelCase doesn’t belong into python code).

I’ve just submitted a very simple pull request in the werkzeug repo to fix this bug. https://github.com/pallets/werkzeug/pull/907

Mixing /a/ and /a seems like a really bad idea to me. Try app.route(.., strict_slashes=False) to disable the automated redirect from /a to /a/ if you really need it though. You can also do this globally using app.url_map.strict_slashes = False

If that solves it for you I’d say it’s not a bug.