当前位置:网站首页>【Flask】Flask启程与实现一个基于Flask的最小应用程序
【Flask】Flask启程与实现一个基于Flask的最小应用程序
2022-07-01 13:29:00 【科皮子菊】
背景
虽然是一名算法工程师,但是实际情况是不仅要懂算法,还要懂工程。算法实现后,算法效果展示,算法落地等就需要一些工程化的内容。算法工程化的一个简单方式就是将落地的算法包装成服务,供他人调用。
那么问题来了,我们需要了解一下服务相关的内容。对外提供服务的方式也有多种方式,例如基于GRPC的服务,基于Restful的api接口服务等。当然,我个人感觉使用基于restful的api接口方式是使用比较多的。于是在了解Python web的相关框架,如Django,Flask, FastAPI等,综合考虑使用Flask去做这项工作。
那么学习一项技术最好的方式是看官方文档,但是官方文档很多内容是接口,方法的使用,枯燥、无味。这里我就通常看有没有Quickstart以及Tutorial,因为这个一方面是主流方法使用的概括。一方面是一个小demo的实现,读起来能够大致了解一项技术包含哪些内容,另一方面可以了解如果使用该技术去完成一些任务。至于更详细的内容,则可以通过查阅文档进一步挖掘知识。
查看Flask文档,恰好有这两部分内容。于是我就开心的学习和记录相关内容了。当然我也不会一口吞一个胖子,很快的阅读完,一段时间学一点记录一点,毕竟自己的主要工作是算法方面的拓展和实践。
当然,后面的记录既是官方文档的翻译也是自己的总结和笔记,献丑啦。
环境准备
flask如何安装可以参考官方网站,本次学习记录主要使用的是2.1.x版本。
为了更好地接近实际工作中的开发方式,我在虚拟机上装了一个centos7系统,并配置了anaconda开发环境。按照flask 2.1.x版本要求Python的版本是3.7+,我也创建了一个python3.7的空开发环境,以便后续可以导出requirements.txt文件。我们可以按照使用venv模块去创建虚拟环境。不过还是比较习惯使用conda去创建虚拟环境,如下:
conda create -n web_flask python=3.7
然后就是在这个环境中安装flask:pip install flask==2.1
下面就是使用pycharm以远程连接的方式连接这个虚拟开发环境了。你可能会想,在自己的虚拟机上开发会不会性能有影响?我觉得这个大可不必担心,这种开发不会吃电脑太多性能。
一个最小应用程序
一个最小的Flask应用可以如下所示:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
上面代码对应的功能如下:
- 导入的Flask类,他是WSGI应用程序的一个实例。如果不清楚这个,可以参考百度词条:wsgi
- 接下来就是对Flask进行实例化。其中第一个参数就是这个应用的模块或者包的名称。
__name__在python中的作用是:第一种情况指的是当前运行的模块,那么当前模块__name__的值就为__main__;第二种情况指的是该模块是使用import导入的模块,那么这个被导入模块的__name__变量的值为该模块的文件名。这是必需的操作,以便 Flask 知道在哪里寻找资源,例如模板和静态文件。 - 当我们使用
route这个装饰器时,就是告诉Flask去这个方法处理什么样的URL链接。 - 该函数返回我们想要在用户浏览器中显示的消息。默认内容类型为 HTML,因此字符串中的 HTML 将由浏览器呈现。
将上面的内容保存到hello.py这个文件中或者使用其他文件名。不过需要确保不是flask.py这个名字,否则会与Flask冲突。
我们使用flask这个命令或者python -m flask去运行这个应用。我们在linux系统hello.py对应文件路径下开始启动他,当然在此之前需要通过导出 FLASK_APP 环境变量来告诉终端要使用的应用程序:
$ export FLASK_APP=hello
$ flask run
于是就有了:
现在是运行起来了,但是只有服务器那台机器可以访问。
应用发现行为:其实flask对于应用启动是有快捷方式的,当服务程序是app.py或者wsgi.py时,就不需要设置FLASK_APP环境变量的。
程序运行起来后,本质上来说是启动了一个非常简单的内置服务器,其应对测试是没有问题的,但是不适合生产中使用。当系统中有其他程序占用了flask的默认端口5000时,启用是会出现OSError:[Errno98]或OSError:[WinError 10013]的错误,这时候则需要更改一下这个程序监听的端口。可以解决的一种方式是在运行命令中添加--port 其他端口号.
当前程序还只能被当前服务器自身访问 ,为了使程序成为一个Extenally Visible Server,可以做的一种方式是在运行开始时添加--host=0.0.0.0,如:flask run --host=0.0.0.0。这就告诉操作系统去监控所有的公网IP了。
根据以上两个问题,汇总开启程序如下:flask run --port 5001 --host=0.0.0.0
在宿主机访问如下:
此外,如果宿主机不能访问的话,可能是虚拟机的系统防火墙的问题,需要打开对5000端口的监听。打开方式可以参见【Centos7】防火墙(firewall)常用命令总结.
Debug模式
flask run命令还可以开启调试模式。通过开启调试模式,如果代码发生变动服务器可以自动加载,并且如果请求期间发生错误,则在浏览器中显示交互式调试器。
需要注意的是:degugger虽然好用,但是最好不要在生产环境中使用,可能会泄露系统的信息。
启动方式:
export FLASK_ENV=development
flask run
HTML转义
flask默认返回的response(响应)是HTML,当然也可以返回json格式的数据等。当返回的内容是HTML时,这时就需要考虑一个问题:injection attacks,flask页面端使用的html渲染引擎是Jinja,将会自动进行防注入攻击处理,就是进行转义。
下面是手动调用的防注入攻击的方式:escape()。为了描述简单,后面的内容都省略了,但是我们需要知道的是,我们是处理的数据都是不可信的数据。
from markupsafe import escape
@app.route("/<name>")
def hello(name):
return f"Hello, {
escape(name)}!"
例如,用户提交的name数据是<script>alert("bad")</script>,那么escape就会将其进行转义,页面端就不会执行这行代码。
可能<name>这种使用方式你还不理解,其就是从URL中获取参数便于服务端根据不同情况处理不同的问题,后面会介绍。
路由Routing
现代 Web 应用程序使用有意义的 URL 来帮助用户。如果页面使用有意义的 URL,他们可以记住并用于直接访问页面,用户更有可能喜欢页面并返回。
每个URL都代表一定意义,根据这些URL指定的意义返回页面是很重要的。于是在flask中,会使用route()这个小东西去绑定一个函数和URL请求。例如:
@app.route('/')
def index():
return 'Index Page'
@app.route('/hello')
def hello():
return 'Hello, World'
其实有了这,我们可以做更多!可以使部分 URL 动态化并将多个规则附加到一个函数。因为前文我们已经看到了可以获取URL中的参数。已经有点Restful接口的意思啦。
可变规则
那么如何动态地搞事情呢?我们可以通过使用 <variable_name> 标记部分来将可变部分添加到 URL中。我们的处理函数接受这个 <variable_name> ,就可以作为函数的参数。除此之外,我们可以使用转换器来指定参数的类型,例如 <converter:variable_name>。使用案例如下:
from markupsafe import escape
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return f'User {
escape(username)}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return f'Post {
post_id}'
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# show the subpath after /path/
return f'Subpath {
escape(subpath)}'
转换参数类型的功能,在低版本的flask是不支持的哦。那么类型转换有哪些呢?如下:
| string | (默认值)接受任何不带斜线的文本 |
|---|---|
| int | 接受正整数 |
| float | 接受正浮点值 |
| path | 像字符串,但也接受斜杠 |
| uuid | 接受 UUID 字符串 |
独特的URLS/重定向行为
以下两条规则在使用斜杠时有所不同。
@app.route('/projects/')
def projects():
return 'The project page'
@app.route('/about')
def about():
return 'The about page'
其中,projects这个URL的尾部有一个斜线"/",这似乎更像一个文件系统中的文件夹。如果您访问的 URL 不带斜杠 (/projects),Flask 会将您重定向到带有斜杠 (/projects/) 的规范 URL。
about 端点的规范 URL 没有尾部斜杠。它类似于文件的路径名。使用尾部斜杠 (/about/) 访问 URL 会产生 404“未找到”错误。这有助于使这些资源的 URL 保持唯一性,从而帮助搜索引擎避免将同一页面编入两次索引。
也就是说,程序中URL中加上斜杠,用户访问的URL没有斜杠时,系统会补全。而程序中URL不加斜杠,用户访问的URL有斜杠时,那么就会报错。
URL构建
要构建特定函数的 URL,可以使用url_for()这个函数。它接受函数的名称作为其第一个参数和任意数量的关键字参数,每个关键字参数对应于 URL 规则的可变部分。未知的可变部分作为查询参数附加到 URL。
那么为什么要使用 URL 反转函数url_for()构建 URL,而不是将它们硬编码到模板中?
- 反转通常比对 URL 进行硬编码更具描述性。
- 您可以一次性更改 URL,而无需记住手动更改硬编码的 URL。
- URL 构建透明地处理特殊字符的转义。
- 生成的路径总是绝对的,避免了浏览器中相对路径的意外行为。
- 如果您的应用程序位于 URL 根之外,例如,在 /myapplication 而不是 / 中,则 url_for() 会为您正确处理。
例如,这里我们使用test_request_context()方法来尝试 url_for()。 test_request_context() 告诉 Flask 表现得好像它正在处理一个请求。
from flask import url_for
@app.route('/')
def index():
return 'index'
@app.route('/login')
def login():
return 'login'
@app.route('/user/<username>')
def profile(username):
return f'{
username}\'s profile'
with app.test_request_context():
print(url_for('index'))
print(url_for('login'))
print(url_for('login', next='/'))
print(url_for('profile', username='John Doe'))
访问结果:
/
/login
/login?next=/
/user/John%20Doe
HTTP协议中方法
Web 应用程序在访问 URL 时使用不同的 HTTP 方法。在使用 Flask 时,您应该熟悉 HTTP 方法。默认情况下,路由只响应 GET 请求。您可以使用 route() 装饰器的方法参数来处理不同的 HTTP 方法。
from flask import request
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return do_the_login()
else:
return show_the_login_form()
上面的示例将路由的所有方法保留在一个函数中,如果每个部分都使用一些公共数据,这将很有用。
您还可以将不同方法的视图分成不同的功能。 Flask 为每种常见的 HTTP 方法提供了一种使用 get()、post() 等装饰此类路由的快捷方式。
@app.get('/login')
def login_get():
return show_the_login_form()
@app.post('/login')
def login_post():
return do_the_login()
如果 GET 存在,Flask 会自动添加对 HEAD 方法的支持并根据 HTTP RFC 处理 HEAD 请求。同样,OPTIONS 会自动为您实施。
总结
码的有点累,下次周末继续搞一波。quickstart不知不觉已过半,加油!!!
边栏推荐
- Report on the "14th five year plan" and scale prospect prediction of China's laser processing equipment manufacturing industry Ⓢ 2022 ~ 2028
- Declare an abstract class vehicle, which contains the private variable numofwheel and the public functions vehicle (int), horn (), setnumofwheel (int) and getnumofwheel (). Subclass mot
- 一款Flutter版的记事本
- 小程序- view中多个text换行
- Etcd 概要 机制 和使用场景
- Applet - applet chart Library (F2 chart Library)
- 7. Icons
- 机器学习总结(一):线性回归、岭回归、Lasso回归
- C语言订餐管理系统
- Interpretation of R & D effectiveness measurement framework
猜你喜欢

面试题目总结(1) https中间人攻击,ConcurrentHashMap的原理 ,serialVersionUID常量,redis单线程,

研发效能度量框架解读

Jenkins+webhooks- multi branch parametric construction-

北斗通信模块 北斗gps模块 北斗通信终端DTU

Cs5268 advantages replace ag9321mcq typec multi in one docking station scheme

Fiori 应用通过 Adaptation Project 的增强方式分享

5G工业网关的科技治超应用 超限超重超速非现场联合执法

详细讲解面试的 IO多路复用,select,poll,epoll

Kongsong (Xintong Institute) - cloud security capacity building and trend in the digital era

The stack size specified is too small, specify at least 328k
随机推荐
3.4 data query in introduction to database system - select (single table query, connection query, nested query, set query, multi table query)
7. Icons
内容审计技术
6年技术迭代,阿里全球化出海&合规的挑战和探索
Interpretation of R & D effectiveness measurement framework
word2vec训练中文词向量
20个实用的 TypeScript 单行代码汇总
spark源码阅读总纲
Social distance (cow infection)
单工,半双工,全双工区别以及TDD和FDD区别
【 剑指 Offer】55 - I. 二叉树的深度
[development of large e-commerce projects] performance pressure test - basic concept of pressure test & jmeter-38
机器学习总结(一):线性回归、岭回归、Lasso回归
Several models of IO blocking, non blocking, IO multiplexing, signal driven and asynchronous IO
孔松(信通院)-数字化时代云安全能力建设及趋势
1.8新特性-List
minimum spanning tree
Kongsong (Xintong Institute) - cloud security capacity building and trend in the digital era
2022 · 让我带你Jetpack架构组件从入门到精通 — Lifecycle
Analysis report on production and marketing demand and investment forecast of global and Chinese diamond powder industry Ⓤ 2022 ~ 2027