Flask中添加自定义转换器(Converter)

目录

Flask 提供的测试服务器对静态文件支持不佳,解析网页的路由与静态文件的路径冲突。在生产环境中,使用 Ngnix 等服务器都支持静态文件,所以可以用生产环境的静态文件 url 代替开发环境的 url。
或者,可以为静态文件配置单独的控制器,使用 {python}send_from_directory{/python} 等函数返回文件。
我尝试使用下面的两个路由设置,没成功。

@app.route('/static/<path:path>')
...
@app.route('/<owner>/<repo>/<path:path>')
...

解析{bash}/static/app/index.js{/bash}文件失败,使用第二个路由(位置问题?有时间再试)。
Stackoverflow上的一个回答给出几种解决方法,其中一种方法使用自定义的转换器(Converter)来设置路由匹配。

Converter

转换器对路由路径中参数进行限定,比如 {python}int{/python} 表示接受int型的路径参数,上面的路由中的{python}path{/python}也是一种转换器,接受包括斜杠(‘/’)的字符串,通常用于路由匹配表达式的最后。
Flask 的转换器(Converter)来自 werkzeug 库,该库还提供自定义转换器的功能。下面我就利用自定义一个转换器来区分静态文件和非静态文件。

Converter 说明

下面是一个来自 werkzeug 库的自定义 Converter 实例。网址

from random import randrange
from werkzeug.routing import Rule, Map, BaseConverter, ValidationError
class BooleanConverter(BaseConverter):
    def __init__(self, url_map, randomify=False):
        super(BooleanConverter, self).__init__(url_map)
        self.randomify = randomify
        self.regex = '(?:yes|no|maybe)'
    def to_python(self, value):
        if value == 'maybe':
            if self.randomify:
                return not randrange(2)
            raise ValidationError()
        return value == 'yes'
    def to_url(self, value):
        return value and 'yes' or 'no'

自定义的 Converter 需要至少定义两个方法:{python}to_python{/python} 和 {python}to_url{/python}。
{python}to_python{/python} 用于将 URL 中的路径转换为 Python 对象,传递给 view 函数。
{python}to_url{/python} 则由 {python}url_for{/python} 调用,将参数转换为 URL 中合适的形式。

识别静态文件的 Converter

从上面的描述很容易能分析出,识别静态文件的 Converter 需要在 to_python 函数中判断当前路径是否属于静态文件。而我的静态文件都放在 static 文件加下,所以只需要检查第一个参数是否为 static 即可。
我创建一个叫 {python}none_static{/python} 的转换器,当路径属于静态文件时,匹配失败。代码如下

class NoStaticConverter(BaseConverter):
    def to_python(self, value):
        if value == 'static':
            raise ValidationError()
        return value
    def to_url(self, value):
        return str(value)

将上面的路由改为

@app.route('/<no_static:owner>/<repo>')

该条路由就不会再匹配静态文件了。