Flask开发
flask不像django那样重量,它非常轻巧,可由程序员自己深度掌控。很适合用来做一些原型快速开发。
一个hello world的例子:
from flask import Flask
import logging
app = Flask(__name__)
@app.route('/')
def hello_world():
app.logger.info('hello called')
return 'hello, lee'
# 这里指定路径参数类型为int,否则flask默认认为是string
@app.route('/repair_plans/page/<int:page_size>/<int:cur_page>')
def query_data(page_size, cur_page):
app.logger.info('size:%d, cur_page:%d' % (page_size, cur_page))
return jsonify(
pageVO = {'totalRows':1},
result = [{'bom':'1', 'repairMethod':'维修', 'battleField':'门店', 'isInherited':True, 'repairTech': '打磨', 'repairTechId':101}]
)
if __name__ == '__main__':
handler = logging.FileHandler('flask.log')
handler.setFormatter(logging.Formatter('[%(process)d|%(thread)d][%(asctime)s] [%(levelname)s] %(message)s'))
app.logger.setLevel(logging.INFO)
app.logger.addHandler(handler)
# 这里使用debug模式,可以自动加载修改,非常方便调试
app.run(debug=True, host='0.0.0.0')
首先,flask使用注解来绑定url和其处理函数,比django更直观,近似于java web框架的做法了。
其次,flask对日志的使用,就跟普通程序里使用logging一样,不用像django那样受限于框架。
获得incoming request和session
直接访问全局变量request和session即可。
构建response
rv = {'status': script.status, 'msg': msg}
Response(json.dumps(rv), mimetype='application/json')
request
flask里的request看起来是一个全局变量,但其实是threadLocal的,可以放心使用,session变量也是类似的情况。参看该文。
另外,flask的request使用了werkzeug库来包装,它提供了一些成员:
request.form 存放的是界面form表单里的数据;
request.json 存放的是请求体里的数据,相当于spring的@RequestBody注解
request.args 存放的是url路径中的参数,类似于spring的@RequestParam注解。
下载文件
有两种方法:
- 将文件放到通过url可访问到的路径
- 使用flask.send_from_directory,可从url不能访问到的路径传输文件
注意
:send_from_directory会做路径检查,确保没有…这样的可能引发安全问题的路径。
flask底层的文件传输有几种策略:
- WSGI server’s file_wrapper support
- X-Sendfile头
静态资源服务
flask的send_static_file实际调用的就是send_from_directory(顺带说一下,网上说send_static_file不安全,其实既然send_from_directory是安全的,那send_static_file就也是安全的!)。因此,flask对静态资源的支持跟文件下载是同一原理。
这里有个问题,是让nginx这样的代理服务器代为管理静态资源(nginx在这方面是非常高效的),还是由flask来处理静态资源?
SO上有一段说明:
The preferred method is to use nginx or another web server to serve static files; they'll be able to do it more efficiently than Flask.
我理解,这里面有2点值得注意:
- 静态资源的缓存问题,为了效率起见,我们不可能每次都去重新传输一个文件;
- 如果有多个flask实例,这些实例间可以共享同一份静态资源,此时可以在多个flask实例前再套一个nginx,由nginx在负载均衡的同时,提供静态资源服务。
flask caching
参考此文。
Blueprint自动添加url前缀
使用Blueprint,可以很方便的为rest请求和静态资源增加url前缀,类似于spring的server.servlet.context-path
先定义蓝图(view.py文件):
main_view = Blueprint('main-view', __name__, static_folder='webapp/')
然后在该蓝图下写路由:
@main_view.route('/')
def home_page():
gen_session_if_needed()
return render_template('index.html',
example_content='',
example_filename='',
prerequisite_content='',
prerequisite_filename='')
最后注册到flask里面:
from view import main_view
app.register_blueprint(main_view)
注意
:蓝图默认不会注册静态资源的路由,需要显示用static_folder来指定。
Blueprint的原理
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.
"""
## f是url的映射函数
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
## 缓存映射函数
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
## 这里记录的是BlueprintSetupState.add_url_rule函数
self.record(lambda s: s.add_url_rule(rule, endpoint, view_func, **options))
def record(self, func):
"""Registers a function that is called when the blueprint is
registered on the application. This function is called with the
state as argument as returned by the :meth:`make_setup_state`
method.
"""
if self._got_registered_once and self.warn_on_modifications:
from warnings import warn
warn(
Warning(
"The blueprint was already registered once "
"but is getting modified now. These changes "
"will not show up."
)
)
self.deferred_functions.append(func)
def register(self, app, options, first_registration=False):
"""Called by :meth:`Flask.register_blueprint` to register all views
and callbacks registered on the blueprint with the application. Creates
a :class:`.BlueprintSetupState` and calls each :meth:`record` callback
with it.
:param app: The application this blueprint is being registered with.
:param options: Keyword arguments forwarded from
:meth:`~Flask.register_blueprint`.
:param first_registration: Whether this is the first time this
blueprint has been registered on the application.
"""
self._got_registered_once = True
## 创建一个BlueprintSetupState
state = self.make_setup_state(app, options, first_registration)
## 处理静态资源
if self.has_static_folder:
state.add_url_rule(
self.static_url_path + "/<path:filename>",
view_func=self.send_static_file,
endpoint="static",
)
## 调用前面缓存的url映射函数
for deferred in self.deferred_functions:
deferred(state)
...
...
## BlueprintSetupState.add_url_rule函数,真正添加flask的url路由的地方
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
"""A helper method to register a rule (and optionally a view function)
to the application. The endpoint is automatically prefixed with the
blueprint's name.
"""
##自动为rule添加url_prefix
if self.url_prefix is not None:
if rule:
rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/")))
else:
rule = self.url_prefix
options.setdefault("subdomain", self.subdomain)
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
defaults = self.url_defaults
if "defaults" in options:
defaults = dict(defaults, **options.pop("defaults"))
# 然后加到flask app的url路由中,由于该函数肯定是在register blueprint之后调,self.app必然已设置
self.app.add_url_rule(
rule,
"%s.%s" % (self.blueprint.name, endpoint),
view_func,
defaults=defaults,
**options
)
总结
:蓝图会事先缓存url映射函数,当注册到flask时(通过app.register_blueprint)才真正去添加url路由。
常见问题
结尾有无反斜杠的区别
我们的根url结尾最好加一个斜杠,否则会找不到链接,故障现象是zuul里压根就没有请求的url。因为我们的代码一般是这么写的:
@main_view.route('/')
def home_page():
gen_session_if_needed()
return render_template('index.html',
example_content='',
example_filename='',
prerequisite_content='',
prerequisite_filename='',
url_prefix=SCIMATE_URL_PREFIX)
这就表示根url最后必须要有一个斜杠。
Flask部署
前端都使用nginx做反向代理及负载均衡。
结合gevent
Flask+gevent+gevent.pywsgi:使用gevent自带的WSGIServer
Flask+gevent+uwsgi: uwsgi里有使用gevent的选项
Flask+gevent+gunicorn:gunicorn里有使用gevent的选项
不使用gevent
Flask+uwsgi
Flask+gunicorn
参考文档:文章来源:https://www.toymoban.com/news/detail-664345.html
flask启动
如果在代码里写了app.run,就可以直接像普通python程序那样运行。
若没写app.run,启动命令:文章来源地址https://www.toymoban.com/news/detail-664345.html
flask run -h 0.0.0.0 -p 8080
到了这里,关于flask使用心得的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!