-
-
Notifications
You must be signed in to change notification settings - Fork 16.2k
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
Automatic redirect with "/" breaks routes with different methods #1783
Comments
Switching the order of the two routes fixes the issue btw: from flask import Flask
app = Flask(__name__)
@app.route("/a", methods=["POST"])
def hello_post():
return "Hello POST!\n"
@app.route("/a/", methods=["GET"])
def hello():
return "Hello GET!\n"
if __name__ == "__main__":
app.run() That way POST does get matched: $ curl localhost:5000/a -L
Hello GET!
$ curl localhost:5000/a -X POST -L
Hello POST! |
Mixing If that solves it for you I'd say it's not a bug. |
I agree that it is not very nice. But I found this bug during a refactor that had the side of importing the routes in a different order and suddenly different parts of my application were broken because there were some GET routes that redirected my PUT routes. It seems bad that routes are redirected when the resulting route will result in a 405 error, especially when the first route was in the routing table for that method. Disabling strict slashes for the GET route in the example works |
Hello @JelteF 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. |
@AzureusNation When using REST like applications I think it is a very weird practice to do it like this. Since the GET, PUT and POST methods probably do entirely different things, but putting them in the same function. It is also shown in examples that you can simple have functions with the same route but with different methods: I've also used this method for more than two years now and have never had any problems with it except the one I'm showing here. |
You could use class-based views or an extension like flask-restful |
@JelteF Here's an idea so not all the code is in the same function. You could have your functions in a separate py file and call the functions like this. @app.route("/hello", methods=["GET", "POST"])
def hello():
if request.method == "POST":
return doPost()
return doGet() But personally I don't see the need of having 3 functions when you can compress it down in to one. |
Pretty ugly IMO (not to mention that camelCase doesn't belong into python code). |
It doesn't look like there's a bug here since the behavior is configurable. Having the strict slashes redirect default to on seems fine to me--I prefer that we have a redirect one way or the other as I think it leads to cleaner URLs by default. If a user for some reason wants to mix the route styles, it's not hard to google how to turn off that redirect. Arguably, the redirect could kick in after the routes table is parsed, in which case the new POST would work, but if you'd previously had a route that was working due to a redirect, adding this new route would (somewhat unexpectedly) break the original route. For now, I'm closing this, if there's significant interest in changing the evaluation order so the redirect happens after the routes table, then we can re-open and re-evaluate. |
The redirect itself is not the problem, since that is exactly what I want. The problem is that it redirects even though the method is invalid after the redirect, especially because the exact route is valid for that method. If a GET route would be defined with and without a slash I would argue that this behaviour is not a bug. But in this case a redirect is done to a route that will definitely return an error in favour of not redirecting and having a route that matches directly. |
FTR changing the evaluation order to anything "complexity-based" seems like a no-go to me since the resulting behavior would be harder to reason about. You're going to end up with edgecases like this one either way: I think the current way has fewer ones. At least you can just change the order of registration to work around it, in systems where the routes are resorted you can't. |
Having thought about this more, I agree the behavior is definitely surprising and does feel like a bug. If a route doesn't define a HTTP method, then another route that handles that method shouldn't be overridden, regardless of auto-redirects. I'm not sure how to best solve it. Probably the redirect should only kick in for the defined HTTP methods on a route. That's the behavior I would expect. |
Sorry, yes, that is a bug. I didn't even sense this from the original post, probably was half-sleeping. While I think this can maybe be solved in a backwards-compatible manner, I don't think it qualifies for a bugfix release, as it might break applications. |
Glad to hear you guys agree. After looking into to Flask internals a bit I think this is actually a Werkzeug bug instead of a Flask bug. |
I've just submitted a very simple pull request in the werkzeug repo to fix this bug. pallets/werkzeug#907 |
Closing, this is now tracked over in pallets/werkzeug#907 Thanks again @JelteF for working on this. |
no please keep this issue open, PRs are different from issues. |
No problem, but I thought the switch to fixing this in Werkzeug means it's not an issue with Flask but with upstream? Do we keep Flask issues open if the underlying problem is in a dependancy? |
It would be better refiled against Werkzeug but more importantly, some issue should stay open. |
I would close this and file it again against Werkzeug. This actually is also related to this issue: pallets/werkzeug#185 (As the flipping of the order of the decorator should not have made a difference) |
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:
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):Edit: My python version is Python3.4 and Werkzeug is 0.11.8 but it was also possible with the git version of Werkzeug.
The text was updated successfully, but these errors were encountered: