Flask 301 Response

15,886

The traceback shows that it was the route matching that raised a redirect; usually (e.g. unless you added explicit redirect routes), that means the client tried to access a branch URL (one that ends with a trailing slash), but the requested URL did not include the last slash. The client is simply being redirected to the canonical branch URL with the slash.

From the Werkzeug Rule documentation:

URL rules that end with a slash are branch URLs, others are leaves. If you have strict_slashes enabled (which is the default), all branch URLs that are matched without a trailing slash will trigger a redirect to the same URL with the missing slash appended.

From the routing documentation:

Flask’s URL rules are based on Werkzeug’s routing module. The idea behind that module is to ensure beautiful and unique URLs based on precedents laid down by Apache and earlier HTTP servers.

Take these two rules:

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'

Though they look rather similar, they differ in their use of the trailing slash in the URL definition. In the first case, the canonical URL for the projects endpoint has a trailing slash. In that sense, it is similar to a folder on a file system. Accessing it without a trailing slash will cause Flask to redirect to the canonical URL with the trailing slash.

In the second case, however, the URL is defined without a trailing slash, rather like the pathname of a file on UNIX-like systems. Accessing the URL with a trailing slash will produce a 404 “Not Found” error.

This behavior allows relative URLs to continue working even if the trailing slash is ommited, consistent with how Apache and other servers work. Also, the URLs will stay unique, which helps search engines avoid indexing the same page twice.

As documented, if you do not want this behaviour (and have the url without the trailing slash be a 404 Not Found instead), you must set the strict_slashes=False option on your route.

Share:
15,886

Related videos on Youtube

Nalum
Author by

Nalum

I like to help when I can.

Updated on June 18, 2022

Comments

  • Nalum
    Nalum almost 2 years

    My flask app is doing a 301 redirect for one of the urls.

    The traceback in New Relic is:

    Traceback (most recent call last):
      File "/var/www/app/env/local/lib/python2.7/site-packages/flask/app.py", line 1358, in full_dispatch_request
        rv = self.dispatch_request()
      File "/var/www/app/env/local/lib/python2.7/site-packages/flask/app.py", line 1336, in dispatch_request
        self.raise_routing_exception(req)
      File "/var/www/app/env/local/lib/python2.7/site-packages/flask/app.py", line 1319, in raise_routing_exception
        raise request.routing_exception
    RequestRedirect: 301: Moved Permanently
    

    It doesn't look like it is even hitting my code or rather the traceback isn't showing any of my files in it. At one point I did have Nginx redirect all non SSL request to HTTPS but had to disable that as Varnish was not able to make the request to port 443 with out an error... probably some configuration that I did or didn't make.

    It doesn't always return a 301 though, I can request the URL and get it without any trouble. But someone out in the world requesting the URL is getting a 301 response.

    It is a GET request with some custom headers to link it to the account.

    At no point in my code is there a 301 redirect.

    • Martijn Pieters
      Martijn Pieters over 10 years
      Are you using something like Flask-Login with a session-based authentication method? In such cases it is common to redirect to the login screen with a 301 redirect.
    • Nalum
      Nalum over 10 years
      This particular page is a simple JSON document, no login is required, but a valid API key in the headers is.
    • Martijn Pieters
      Martijn Pieters over 10 years
      Werkzeug by default redirects to the version with the / if the route is mapped to a path ending in / but accessed without the /.
    • Ryan O'Donnell
      Ryan O'Donnell over 10 years
      Can we see the route/code?