29
votes

Take for example the following two routes.

app = Flask(__name__)

@app.route("/somewhere")
def no_trailing_slash():
    #case one

@app.route("/someplace/")
def with_trailing_slash():
    #case two

According to the docs the following is understood:

  • In case one, a request for the route "/somewhere/" will return a 404 response. "/somewhere" is valid.

  • In case two, "/someplace/" is valid and "/someplace" will redirect to "/someplace/"

The behavior I would like to see is the 'inverse' of the case two behavior. e.g. "/someplace/" will redirect to "/someplace" rather than the other way around. Is there a way to define a route to take on this behavior?

From my understanding, strict_slashes=False can be set on the route to get effectively the same behavior of case two in case one, but what I'd like to do is get the redirect behavior to always redirect to the URL without the trailing slash.

One solution I've thought of using would be using an error handler for 404's, something like this. (Not sure if this would even work)

@app.errorhandler(404)
def not_found(e):
    if request.path.endswith("/") and request.path[:-1] in all_endpoints:
        return redirect(request.path[:-1]), 302
    return render_template("404.html"), 404

But I'm wondering if there's a better solution, like a drop-in app configuration of some sort, similar to strict_slashes=False that I can apply globally. Maybe a blueprint or url rule?

3
implement both seperately and have /somplace/ redirect to /someplace?Busturdust
What I have noticed is when you have DEBUG=True in your Flask config the trailing spaces are not redirected but when DEBUG=False then it is redirected.kiran.koduru
@Busturdust that could probably work, but would be kind of a pain to manage. Some other ideas I've had involve using an error handler that returns a redirect if the slashless endpoint exists. It may also be possible to use a blueprint of some sort. But I already use a 404 error handler for something else (it could be baked in, but I'd rather not) and I'm not sure if it can be achieved with a blueprint. The ideal solution would be a drop-in like a global url rule.sytech
@kiran.koduru That's an interesting observation. I'll have to take a look at that, although I don't think I'll be using the debug flag in production, for obvious reasons. I typically deploy Flask using Tornado or gEvent. Even when I set app.debug = True it doesn't appear to take in the gevent WSGI environment. I'm sure there's a way to solve that problem, but is another question and as explained, probably not an applicable solution to this question, for a production environment.sytech

3 Answers

52
votes

You are on the right tracking with using strict_slashes, which you can configure on the Flask app itself. This will set the strict_slashes flag to False for every route that is created

app = Flask('my_app')
app.url_map.strict_slashes = False

Then you can use before_request to detect the trailing / for a redirect. Using before_request will allow you to not require special logic to be applied to each route individually

@app.before_request
def clear_trailing():
    from flask import redirect, request

    rp = request.path 
    if rp != '/' and rp.endswith('/'):
        return redirect(rp[:-1])
7
votes

If you want both routes to be handled the same way, I would do this:

app = Flask(__name__)

@app.route("/someplace/")
@app.route("/someplace")
def slash_agnostic():
    #code for both routes
0
votes

You can also use the option strict_slashes=False in your route definition:

app.Flask(__name__)
@app.route("/someplace", strict_slashes=False)
# Your code goes here