flask基础总结

622 阅读8分钟

程序运行过程

此时,Web服务器使用WSGI(Web Server Gateway Interface)协议,把来自客户端的所有请求都交给Flask程序实例。WSGI是为 Python 语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口,它封装了接受HTTP请求、解析HTTP请求、发送HTTP,响应等等的这些底层的代码和操作,使开发者可以高效的编写Web应用。

程序实例使用Werkzeug来做路由分发(URL请求和视图函数之间的对应关系)。根据每个URL请求,找到具体的视图函数。 在Flask程序中,路由的实现一般是通过程序实例的route装饰器实现。route装饰器内部会调用add_url_route()方法实现路由注册。

Flask装饰器路由的实现

Flask有两大核心:Werkzeug和Jinja2。Werkzeug实现路由、调试和Web服务器网关接口。Jinja2实现了模板。

Werkzeug是一个遵循WSGI协议的python函数库。其内部实现了很多Web框架底层的东西,比如request和response对象;与WSGI规范的兼容;支持Unicode;支持基本的会话管理和签名Cookie;集成URL请求路由等。

Werkzeug库的routing模块负责实现URL解析。不同的URL对应不同的视图函数,routing模块会对请求信息的URL进行解析,匹配到URL对应的视图函数,以此生成一个响应信息。

routing模块内部有Rule类(用来构造不同的URL模式的对象)、Map类(存储所有的URL规则)、MapAdapter类(负责具体URL匹配的工作)

查看视图函数中的路由

返回状态码示例

return后面可以自主定义状态码(即使这个状态码不存在)。当客户端的请求已经处理完成,由视图函数决定返回给客户端一个状态码,告知客户端这次请求的处理结果。

from flask import Flask

app = Flask(__name__) 


@app.route('/')
def hello():
    return 'hello python', 999


if __name__ == "__main__": 
    app.run(debug=True)

测试响应的状态码:

abort函数

如果在视图函数执行过程中,出现了异常错误,我们可以使用abort函数立即终止视图函数的执行。通过abort函数,可以向前端返回一个http标准中存在的错误状态码,表示出现的错误信息。

使用abort抛出一个http标准中不存在的自定义的状态码,没有实际意义。如果abort函数被触发,其后面的语句将不会执行。其类似于python中raise。

from flask import Flask, abort

app = Flask(__name__) 


@app.route('/')
def hello_itcast():
    abort(404)
    return 'hello python',999


if __name__ == "__main__": 
    app.run(debug=True)

响应结果:

异常捕获

在Flask中通过装饰器来实现捕获异常,errorhandler()接收的参数为异常状态码。视图函数的参数,返回的是错误信息。

from flask import Flask, abort

app = Flask(__name__) 


@app.route('/')
def hello_itcast():
    abort(404)
    return 'hello python', 999


@app.errorhandler(404)
def error(e):
    return '您请求的页面不存在了,请确认后再次访问!%s'%e


if __name__ == "__main__": 
    app.run(debug=True)

响应结果:

重定向

from flask import Flask, redirect

app = Flask(__name__) 


@app.route('/')
def hello():
    return redirect('http://www.google.com')


if __name__ == "__main__": 
    app.run(debug=True)

正则url

正则URL是为了匹配指定的URL,而匹配指定的URL则可以达到限制访问,以及优化访问路径的目的。

from flask import Flask
from werkzeug.routing import BaseConverter


class Regex_url(BaseConverter):
    def __init__(self, url_map, *args):
        super(Regex_url, self).__init__(url_map)
        self.regex = args[0]


app = Flask(__name__)
app.url_map.converters['re'] = Regex_url


@app.route('/user/<re("[a-z]{3}"):id>')
def hello(id):
    return 'hello %s' %id


if __name__ == "__main__": 
    app.run(debug=True)

获取 cookie 以及 session

from flask import Flask, make_response

app = Flask(__name__)


@app.route('/cookie')
def set_cookie():
    resp = make_response('this is to set cookie')
    resp.set_cookie('username', 'ruiyang')
    return resp


if __name__ == "__main__": 
    app.run(debug=True)

在设置cookie之后再次请求,就会在请求头中看到为客户端设置的cookie:

另外一种查看方式:

from flask import Flask, make_response, request

app = Flask(__name__)


@app.route('/cookie')
def set_cookie():
    resp = make_response('this is to set cookie')
    resp.set_cookie('username', 'ruiyang')
    return resp


@app.route('/request')
def resp_cookie():
    resp = request.cookies.get('username')
    return resp


if __name__ == "__main__": 
    app.run(debug=True)

然后请求 /request ,结果:

上下文

上下文:相当于一个容器,保存了Flask程序运行过程中的一些信息。

Flask中有两种上下文,请求上下文和应用上下文。

请求上下文

request和session都属于请求上下文对象。

request:封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。

session:用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息。

应用上下文

current_app和g都属于应用上下文对象。

current_app:表示当前运行程序文件的程序实例。我们可以通过current_app.name打印出当前应用程序实例的名字。

g:处理请求时,用于临时存储的对象,每次请求都会重设这个变量。比如:我们可以获取一些临时请求的用户信息。

  • 当调用app = Flask(name)的时候,创建了程序应用对象app;
  • request 在每次http请求发生时,WSGI server调用Flask.call();然后在Flask内部创建的request对象;
  • app的生命周期大于request和g,一个app存活期间,可能发生多次http请求,所以就会有多个request和g。
  • 最终传入视图函数,通过return、redirect或render_template生成response对象,返回给客户端。

区别: 请求上下文:保存了客户端和服务器交互的数据。 应用上下文:在flask程序运行过程中,保存的一些配置信息,比如程序文件名、数据库的连接、用户信息等。

请求钩子

在客户端和服务器的交互中,有些准备工作或扫尾工作需要处理,比如:在请求开始时,建立数据库连接;在请求结束时,指定数据的交互格式。为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子。

请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:

  • before_first_request:在处理第一个请求前运行。

  • before_request:在每次请求前运行。

  • after_request:如果没有未处理的异常抛出,在每次请求后运行。

  • teardown_request:在每次请求后运行,即使有未处理的异常抛出。

反向路由

Flask提供了url_for()辅助函数,可以使用程序URL映射中保存的信息生成URL;url_for()接收视图函数名作为参数,返回对应的URL;

如调用url_for('index',_external=True)返回的是绝对地址,在下面这个示例中是http://127.0.0.1:5000/index

from flask import Flask, url_for
from flask_script import Manager

app = Flask(__name__)

manager = Manager(app)


@app.route('/index')
def index():
    return "hello"


@app.route('/user/')
def redirect():
    return url_for('index', _external=True)


if __name__ == "__main__":
    manager.run()

flask 代码结构分析

最简结构

我们可以使用几行代码创建一个完整的 flask app: 参见: palletsprojects.com/p/flask/

from flask import Flask, escape, request

app = Flask(__name__)


@app.route('/')
def hello():
    name = request.args.get("name", "World")
    return f'Hello, {escape(name)}!'

设置环境变量并且尝试运行:

env FLASK_APP=hello.py flask run

基础结构

我们会尝试实现一个稍微更复杂的例子,为我们编写更大的应用程序提供一个很好的基础结构。 在项目目录下(也就是microblog目录下)创建一个 app 的包来放真个应用: mkdir app 进入 app,在其中创建文件 init.py 并且输入以下代码:

from flask import Flask 

app = Flask(__name__)

from app import routes

我们来分析下这个脚本,它从 flask 中导入了 Falsk, 并且以此创建了一个应用程序对象。 传递给Flask类的__name__变量是一个Python预定义的变量,它表示当前调用它的模块的名字。 当需要加载相关的资源,例如模板文件时,Flask就使用这个位置作为起点来计算绝对路径。 代码的最后,应用程序导入尚未存在的routes模块。

这段代码,乍一看可能会让人迷惑。

其一,这里有两个实体名为app。 app包由app目录和__init__.py脚本来定义构成,并在from app import routes语句中被引用。 app变量被定义为__init__.py脚本中的Flask类的一个实例,以至于它成为app包的属性。

其二,routes模块是在底部导入的,而不是在脚本的顶部。 最下面的导入是解决循环导入的问题,这是Flask应用程序的常见问题。 你将会看到routes模块需要导入在这个脚本中定义的app变量,因此将routes的导入放在底部可以避免由于这两个文件之间的相互引用而导致的错误。

这是需要写入到app/routes.py中的第一个视图函数的代码:

from app import app

@app.route('/')
@app.route('/index')
def index():
    return "Hello, World!"

要完成应用程序,你需要在定义Flask应用程序实例的顶层, 创建一个例如命名为microblog.py的Python脚本。 它仅拥有一个导入应用程序实例的行: from app import app

还记得两个app实体吗? 在这里,你可以在同一句话中看到两者。 Flask应用程序实例被称为app,是app包的成员。from app import app语句从app包导入其成员app变量。

这时候我们的项目目录如下: microblog/ app/ init.py routes.py microblog.py

这个应用的第一个版本现在完成了! 但是在运行之前,需要通过设置FLASK_APP环境变量告诉Flask如何导入它: export FLASK_APP=microblog.py

运行如下命令来运行我们的第一个Web应用: flask run

服务启动后将处于阻塞监听状态,将等待客户端连接。 flask run的输出表明服务器正在运行在IP地址127.0.0.1上,这是本机的回环IP地址。 这个地址很常见,并有一个更简单的名字,你可能已经看过:localhost。 网络服务器监听在指定端口号等待连接。 部署在生产Web服务器上的应用程序通常会在端口443上进行监听,如果不执行加密,则有时会监听80,但启用这些端口需要root权限。 由于此应用程序在开发环境中运行,因此Flask使用自由端口5000。