Python进阶(五十)-解析Flask运行原理

举报
SHQ5785 发表于 2020/12/29 23:49:41 2020/12/29
【摘要】 #Python进阶(五十)-解析Flask运行原理   在学习Python Web开发过程中,掌握了Flask的开发方法。经过一段时间的视频学习,回过头来对Flask的运行原理做一简要解析,以增强自己对Flask的了解。   所有的 Python Web框架都要遵循 WSGI 协议,在这里还是要简单回顾一下 WSGI 的核心概念。   WSGI 中有一个非常重要的概念:...

#Python进阶(五十)-解析Flask运行原理
  在学习Python Web开发过程中,掌握了Flask的开发方法。经过一段时间的视频学习,回过头来对Flask的运行原理做一简要解析,以增强自己对Flask的了解。
  所有的 Python Web框架都要遵循 WSGI 协议,在这里还是要简单回顾一下 WSGI 的核心概念。
  WSGI 中有一个非常重要的概念:每个Python Web应用都是一个可调用(callable)的对象。在 flask 中,这个对象就是 app = Flask(name) 创建出来的 app,就是下图中的绿色Application部分。要运行web应用,必须有 web server,比如我们熟悉的apache、nginx,或者python中的gunicorn,我们下面要讲到的werkzeug提供的WSGIServer,它们是下图的黄色Server部分。
这里写图片描述
  Server和Application之间怎么通信,就是WSGI的功能。它规定了 app(environ, start_response) 的接口,server会调用 application,并传给它两个参数:environ 包含了请求的所有信息,start_response 是 application 处理完之后需要调用的函数,参数是状态码、响应头部还有错误信息。
  WSGI application 非常重要的特点是:它是可以嵌套的。换句话说,可以写个application,它做的事情就是调用另外一个 application,然后再返回(类似一个 proxy)。一般来说,嵌套的最后一层是业务应用,中间就是 middleware。这样的好处是,可以解耦业务逻辑和其他功能,比如限流、认证、序列化等都实现成不同的中间层,不同的中间层和业务逻辑是不相关的,可以独立维护;而且用户也可以动态地组合不同的中间层来满足不同的需求。
这里写图片描述
  Flask基于Werkzeug WSGI工具箱和Jinja2 模板引擎。 Flask使用BSD授权。 Flask也被称为“microframework”,因为它使用简单的核心,用extension增加其他功能。Flask没有默认使用的数据库、窗体验证工具。然而,Flask保留了扩增的弹性,可以用Flask-extension加入这些功能:ORM、窗体验证工具、文件上传、各种开放式身份验证技术。我们可以这么理解,Flask是一个核心,而其他功能则是一些插件,需要什么功能,只要找到对应的插件,将其插入核心就能够实现该功能了。
  Flask是怎么将代码转换为我们可见的Web网页的。首先,我们得先从Web程序的一般流程来看,对于我们的Web应用来说,当客户端想要获取动态资源 时,(比如ASP和PHP这类语言写的网站),这个时候就会发起一个HTTP请求(比如用浏览器访问一个URL),此时Web应用程序就会在服务器后台进行相应的业务处理(比如对数据库进行操作或是进行一些计算操作等),取出用户需要的数据,生成相应的HTTP响应(当然,如果访问的是 静态资源 ,服务器则会直接返回用户所需的资源,不会进行业务处理)。整个处理工程如下所示:
这里写图片描述
  在实际的应用中,不同的请求可能会调用相同的处理逻辑。这里有着相同业务处理逻辑的HTTP请求可以用一类URL来标识。比如在我们的博客站点中,对于所有想要获取Articles内容的请求而言,可以用 articles/这类URL来表示,这里的article_id用以区分不同的article。接着在后台定义一个get_article(article_id)的函数,用来获取article相应的数据,此外还需要建立URL和函数之间的一一对应关系。这就是Web开发中所谓的路由分发 ,如下图所示:
这里写图片描述
  在Flask中,使用werkzeug来做路由分发,werkzeug是Flask使用的底层WSGI库(WSGI,全称 Web Server Gateway interface,或者 Python Web Server Gateway Interface,是为 Python 语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口)。
  WSGI将Web服务分成两个部分:服务器和应用程序。WGSI服务器只负责与网络相关的两件事:接收浏览器的HTTP请求、向浏览器发送HTTP应答;而对HTTP请求的具体处理逻辑,则通过调用WSGI应用程序进行。WSGI工作流程如下图所示:
这里写图片描述
  在Flask中,路由分发的代码写起来十分简单,如下:

# 管理员注销页面
@main.route('/logout')
def logout(): dm = DataManager() currentUsers = dm.getUsers('0') print(currentUsers[0]) return render_template('currentUsers.html', users=currentUsers)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

  通过业务逻辑函数获得我们所需的数据后,服务器将会根据这些数据来生成HTTP响应(对于Web应用来说,一般就是一个HTML文件,这个是可以直接被我们的客户端,即浏览器直接读取并解释的)。在Web开发中,常规的做法是将获取的数据传入Web应用提供的一个HTML模板文件中,经过模板系统的渲染后最终得到我们所需要的HTML响应文件。
  一般情况下,虽然请求不同,但是响应中的数据的展示方式是相同的 ,通俗点说就是除了我们请求获得的数据不一样外,其他都是一样的,那么我们就可以设计一个模板(除了数据内容可以改动,其他都是固定的HTML文件)。我们以博客站点为例,对不同article而言,其具体article content虽然不同,但页面展示的内容除了请求的数据外都是一样的,都有标题拦,内容栏等。也就是说,对于article来说,我们只需提供一个HTML模板,然后传入不同article数据,即可得到不同的HTTP响应。这就是所谓的模板渲染 ,如下图所示:
这里写图片描述
  在Flask中使用Jinja2模板渲染引擎来做模板渲染(Jinja2是基于python的模板引擎,功能比较类似于于PHP的smarty,J2ee的Freemarker和velocity。它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛。jinja2使用BSD授权)。Jinja2的工作流程如下图所示:
这里写图片描述
  在Flask中,模板渲染的代码写起来也是十分的便捷,代码如下:

@app.route('/articles/<int:article_id>/') 
defget_article(article_id):
returnrender_template('path/to/template.html', data_needed)

  
 
  • 1
  • 2
  • 3

  在Flask中,我们处理一个请求的流程就是,首先根据用户提交的URL来决定由哪个业务逻辑函数来处理,然后在函数中进行操作,取得所需的数据。再将取得的数据传给相应的模板文件中,由Jinja2负责渲染得到HTTP响应内容,即HTTP响应的HTML文件,然后由Flask返回响应内容。
  下面主要以实例项目对Flask运行原理做一简要解析。在实例项目中,使用到了程序工厂函数和蓝本。项目目录结构如下:
这里写图片描述
  在manager.py文件中,定义了项目启动的入口函数:

# 确保服务器只会在该脚本被 Python 解释器直接执行的时候才会运行,而不是作为模块导入的时候。
if __name__ == '__main__': # 启用cmd命令行 # manager.run() app.run(host='0.0.0.0', port=9000, debug=True)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

同时,在该文件中创建了工厂方法实例:

	app = create_app()

  
 
  • 1

  在工程方法中,对数据库进行了相关配置,创建了前端导航栏,同时对所创建的蓝本进行了注册。在创建的蓝本中主要涉及授权、路由及错误处理模块。

# 构造工厂方法
def create_app(): # 在这里__name__ == __main__ app = Flask(__name__) app.url_map.converters['regex'] = RegexConverter # 防止跨站攻击 注:为了增强安全性,密钥不应直接写入代码,而应该保存在环境变量中 # app.config['SECRET_KEY'] = 'hard to guess string SUNNY2017' # app.secret_key = 'Sunny123456' # flask提供的读取外部文件 app.config.from_pyfile('config') # basedir = os.path.abspath(os.path.dirname(__file__)) # print(basedir) # 配置数据库连接 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://lmapp:lmapp@localhost/smp' app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True nav.register_element('top', Navbar(u'APP安盾', View(u'当前在线', 'main.index'), View(u'全部用户', 'main.all_users'), View(u'注销', 'main.logout'), View(u'修改密码', 'main.chgpwd'), )) nav.init_app(app) db.init_app(app) bootstrap.init_app(app) # init_views(app) from .auth import auth as auth_blueprint from .main import main as main_blueprint # 注册蓝本 url_prefix='/auth' app.register_blueprint(auth_blueprint,) app.register_blueprint(main_blueprint, static_folder='static') return app

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

文章来源: shq5785.blog.csdn.net,作者:No Silver Bullet,版权归原作者所有,如需转载,请联系作者。

原文链接:shq5785.blog.csdn.net/article/details/72808619

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

举报
请填写举报理由
0/200