一、Web 服务器与 Web 框架
首先明确一下,要运行一个动态网页,我们需要
- 一个 Web 服务器来监听并响应请求
- 一个 Web 应用来处理请求,生成响应
其中 Web 服务器通常都是别人已经实现好了的,它通过定义好的接口与我们编写的 Web 应用通信。WSGI 就是一个统一的 Web 服务器接口标准,如果我们按照 WSGI 编写 Web 应用,那么它就能在任何符合该标准的服务器上运行,例如 Gunicorn 和 uWSGI + nginx。(对比一下 Java 的 Servlet,按照 Servlet 规范编写的应用,都能运行在任何 Servlet 容器上,例如 Tomcat 和 Jetty,Servlet 容器就相当于 WSGI 服务器)
可是 WSGI 仍然比较底层,直接照着它写太麻烦,于是就有了 Web 框架,Python 知名的就是 Flask 和 Django,Java 对应的是 Spring MVC. 但是 Flask 和 Django 都有内置服务器用于测试,而 Spring MVC 没有,倒是 Spring Boot 可以使用内嵌的 tomcat 容器。
二、Flask
Flask 是一个微框架,“微”是指它的核心非常小,任何可选的功能都不包括在内。但是 Flask 社区提供了丰富的拓展插件,你可以通过选择需要的插件来实现你想要的功能。
中间略过 n 万字。。。
三、上下文 Context
1. 请求上下文 Request Context
Java 的 Spring MVC 将请求作为方法参数传入,而且要求参数必须映射到某个类型或者某个 model 上。
Flask 的处理方式与之不同,它提供了一个全局代理对象——request,只要是在请求从开始到结束的过程中,都可以直接通过这个 request 访问 HTTP 请求的各种参数。
请求上下文在请求开始时被压入栈,这时 request 对象才可用,在请求结束后会立即被 pop 出来。
2. 应用上下文 Application Context
一个 app,就是一个 Flask 实例,通过 app = Flask(__name__)
创建。
在请求到来时,除了请求上下文被入栈,还有应用上下文也会被入栈。
请求结束时,它先 pop 出请求上下文,然后是应用上下文。
也就是说在请求过程中,应用上下文是可用的,这时可以通过 current_app 访问当前 app 的相关数据。
疑问
- 在 flask 初始化时,我们不是已经通过
app = Flask(__name__)
创建了一个 app 实例了么?直接用它不行么?
这是因为所有的 flask 模块都需要在 app 对象中注册,在其它模块导入 app 会出现循环导入的问题。
3. g 对象
g 对象,名称来源于 global
,保存在应用上下文中,指应用上下文中的全局变量。
应用上下文只是对当前 app 的一个代理,它的生命周期和请求上下文相同,因此 g 显然也只存在于当前请求过程中,不能用于跨请求传递数据。
4. session 对象
session 位于 请求上下文中,但是它的内容会被保存到 cookie 中,发送到客户端。每次收到请求时又会从 cookie 中加载它。因此它可用于跨请求传输数据。
但是 session 不是安全的数据保存方式,只适合存放非敏感数据。
四、插件
- python-dotenv:配置文件
- flask_wtform:表单
- flask-login:登录与权限验证
- flask-sqlalchemy + flask-migrate:数据库
- flask-restplus:restful api
- flask-SocketIO:websocket
四、使用 blueprint(蓝图)
入门级 flask app 都是单文件应用,当复杂度上升,我们可以把单文件应用分成多个文件,比如:views.py、models.py、forms.py、errors.py。
但是如果项目继续增大,各个文件也会渐渐变得难以维护。views.py 中各种功能的视图函数混在一起,models.py 和 forms.py 也是。显然我们可以按功能,继续分割这几个代码文件。
blueprint 就是用于应对大型项目开发的功能,使用它可以对上述的文件按功能做进一步的拆分。
蓝图使用起来就像应用当中的子应用一样,可以有自己的模板,静态目录,有自己的视图函数和URL规则,蓝图之间互相不影响。但是它们又属于应用中,可以共享应用的配置。
实际上 BluePrint 类的使用也几乎和 Flask 一模一样。差别只是 BluePrint 最后还需要在 Flask 实例中注册:app.register_blueprint(<blue_print_obj>)
.
注意事项
- url_for 的第一个参数 endpoint,是 view function 的名称,不是 route 路径!
- 使用 blueprint 时,endpoint 为
蓝图名称.视图函数名称
- 使用 blueprint 时,endpoint 为
- 读取资源文件:资源文件可以放在
data
文件夹下,使用flask.open_resources("data/<file_name>", mode="rb")
读取资源文件。- 不放在
static
下的原因是,该目录内的文件是可以直接通过 URI/static/<file_path>
访问的,是公开的。我们一般不希望用户直接访问这种资源文件。
- 不放在