无论是Django,还是Flask或者别的web框架的路由的目的都是建立url和函数的对应关系。
对于Flask,他的路由使用装饰器来完成。
最简单的路由
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@app.route('/') def index(): return 'Index Page' @app.route('/hello') def hello(): return 'Hello World'
route() 装饰器把一个函数绑定到对应的 URL 上。
动态路由
我们经常看到类似http://www.cnblogs.com/yangshl/的url。这里的yangshl是我的博客园的用户名。在Fask中也有带变量的路由。
给 URL 增加变量的部分,把一些特定的字段标记作为参数传入到函数中。当然也可以指定一个可选的转换器通过规则 。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@app.route('/<path:username>/<pid>/hello') def hello_world(pid, username): print("pid", pid) print("username", username) return 'Hello World!'
若url是:http://127.0.0.1:8090/kelly/hi/28/hello
则我们截取到
pid 28
username kelly/hi
这说明函数中参数的顺序可以和url中变量的顺序不一致,他们是按照关键字来传参的。而且路由的前后都可以固定的url部分。
其中:path是路由转换器。
实际上Flask有如下几个路由转换器:
- 'default': <class 'werkzeug.routing.UnicodeConverter'>
- 'string': <class 'werkzeug.routing.UnicodeConverter'>
- 'any': <class 'werkzeug.routing.AnyConverter'>
- 'path': <class 'werkzeug.routing.PathConverter'>
- 'int': <class 'werkzeug.routing.IntegerConverter'>
- 'float': <class 'werkzeug.routing.FloatConverter'>
- 'uuid': <class 'werkzeug.routing.UUIDConverter'>
我们通过url传递的变量都是字符串,可以通过转换器来来进行转换类型和规定它匹配的格式。比如int,若我么传入了abc,则不匹配,会报404错误。
自定义路由转换器。
class RegexConverter(BaseConverter): def __init__(self, map, *args): self.map = map self.regex = args[0]
# 注册转换器
app.url_map.converters['regex'] = RegexConverter
@app.route('/view/<regex("[0-9\.,]+"):uuid>/')
def view(uuid):
return "view uuid: %s" % (uuid)
再进一步:self.regex到底是什么?
Flask(其实是Werkzeug)使用Converter把URL中特殊部分(<regex("[a-zA-Z0-9]+"):uuid>)转换为Python变量,通用格式是<converter(args):var_name>。在这个例子中,一个叫regex的converter把URL中相应字段转换为view()中的uuid变量。
因此,converter的regex就是用来判断这串字符是否符合转换格式,ok就转换,否则跳过。对于IntegerConverter来说,"abc"显然无能为力。也就是说,其实Werkzeug的路由本来就支持用正则表达式。string、int、float等都是从它派生出来的(可以看看IntegerConverter等built-in Converter的regex)。
至于为什么不显式地支持,我猜可能是因为正则表达式不容易写好,buggy。
反向路由
本质是根据函数名反向生成url,使用函数 url_for() 来针对一个特定的函数构建一个 URL。它能够接受函数名作为第一参数,以及一些关键字参数, 每一个关键字参数对应于 URL 规则的变量部分。未知变量部分被插入到 URL 中作为查询参数。
with app.test_request_context():
print(url_for('hello_world', username = 'kelly', pid = '12'))
则得到的url是:/kelly/12/hello
若url_for('hello_world', username = 'kelly', pid = '12', _external=True)则返回完整路径:
http://localhost/kelly/12/hello
反向路由在Jinja2中也有使用,用于引入一些静态文件。
总之:路由是url和处理函数之间的桥梁。