在 Flask 路径规则中,尾部斜杠触发404

我想重定向任何路径下的 /users到一个静态应用程序。下面的视图应该捕获这些路径并提供适当的文件(它只打印这个示例的路径)。这适用于 /users/users/604511/users/604511/action。为什么路径 /users/会导致404错误?

@bp.route('/users')
@bp.route('/users/<path:path>')
def serve_client_app(path=None):
return path
44294 次浏览

It's because of Werkzeug’s consistency with other HTTP servers. Have a look at Flask's Quickstart documentation. The relevant paragraph:

Unique URLs / Redirection Behavior

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 omitted, consistent with how Apache and other servers work. Also, the URLs will stay unique, which helps search engines avoid indexing the same page twice.

So just add /users/ as well to the routing.

Your /users route is missing a trailing slash, which Werkzeug interprets as an explicit rule to not match a trailing slash. Either add the trailing slash, and Werkzeug will redirect if the url doesn't have it, or set strict_slashes=False on the route and Werkzeug will match the rule with or without the slash.

@app.route('/users/')
@app.route('/users/<path:path>')
def users(path=None):
return str(path)


c = app.test_client()
print(c.get('/users'))  # 302 MOVED PERMANENTLY (to /users/)
print(c.get('/users/'))  # 200 OK
print(c.get('/users/test'))  # 200 OK
@app.route('/users', strict_slashes=False)
@app.route('/users/<path:path>')
def users(path=None):
return str(path)


c = app.test_client()
print(c.get('/users'))  # 200 OK
print(c.get('/users/'))  # 200 OK
print(c.get('/users/test'))  # 200 OK

You can also set strict_slashes for all URLs.

app.url_map.strict_slashes = False

However, you should avoid disabling strict slashes in most cases. The docs explain why:

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

To disable strict slashes GLOBALLY; set url_map.strict_slashes = False like so:

app = Flask(__name__)
app.url_map.strict_slashes = False

This way you do not have to use strict_slashes=False for each view.

Then you just define the route without a trailing slash like so:

bp = Blueprint('api', __name__, url_prefix='/api')
@bp.route('/my-route', methods=['POST'])

Then /my-route and /my-route/ both work identically.