Flask 实战:3、启动开发服务器

本贴最后更新于 1894 天前,其中的信息可能已经时移世易

Flask 内置了一个简单的开发服务器(由依赖包 Werkzeug 提供),足够在开发和测试阶段使用。

注意
在生产环境需要使用性能够好的生产服务器,以提升安全和性能,具体在本书第三部分会进行介绍。

1、Run,Flask,Run!

Flask 通过依赖包 Click 内置了一个 CLI(Command Line Interface,命令行交互界面)系统。当我们安装 Flask 后,会自动添加一个 flask 命令脚本,我们可以通过 flask 命令执行内置命令、扩展提供的命令或是我们自己定义的命令。其中,flask run 命令用来启动内置的开发服务器:

$ flask run
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

注意
确保执行命令前激活了虚拟环境(pipenv shell),否则需要使用 pipenv run flask run 命令启动开发服务器。后面将不再提示。

你可以执行 flask --help 查看所有可用的命令。

提示
如果执行 flask run 命令后显示命令未找到提示(command not found)或其他错误,可以尝试使用 python-m flask run 启动服务器,其他命令亦同。

flask run 命令运行的开发服务器默认会监听 http://127.0.0.1:5000/ 地址(按 Crtl+C 退出),并开启多线程支持。当我们打开浏览器访问这个地址时,会看到网页上显示“Hello,World!”,如图 1-5 所示。

image.png

图 1-5 “Hello,World!”程序主页

提示
http://127.0.0.1 即 localhost,是指向本地机的 IP 地址,一般用来测试。Flask 默认使用 5000 端口,对于上面的地址,你也可以使用 http://localhost:5000/ 。在本书中这两者会交替使用,除了地址不同外,两者没有实际区别,即域名和 IP 地址的映射关系。

旧的启动开发服务器的方式是使用 app.run()方法,目前已不推荐使用(deprecated)。

1.自动发现程序实例

一般来说,在执行 flask run 命令运行程序前,我们需要提供程序实例所在模块的位置。我们在上面可以直接运行程序,是因为 Flask 会自动探测程序实例,自动探测存在下面这些规则:

  • 从当前目录寻找 app.py 和 wsgi.py 模块,并从中寻找名为 app 或 application 的程序实例。
  • 从环境变量 FLASK_APP 对应的值寻找名为 app 或 application 的程序实例。

因为我们的程序主模块命名为 app.py,所以 flask run 命令会自动在其中寻找程序实例。如果你的程序主模块是其他名称,比如 hello.py,那么需要设置环境变量 FLASK_APP,将包含程序实例的模块名赋值给这个变量。Linux 或 macOS 系统使用 export 命令:

$ export FLASK_APP=hello

在 Windows 系统中使用 set 命令:

> set FLASK_APP=hello

2.管理环境变量

Flask 的自动发现程序实例机制还有第三条规则:如果安装了 python-dotenv,那么在使用 flask run 或其他命令时会使用它自动从.flaskenv 文件和.env 文件中加载环境变量。

附注
当安装了 python-dotenv 时,Flask 在加载环境变量的优先级是:手动设置的环境变量 >.env 中设置的环境变量 >.flaskenv 设置的环境变量。

除了 FLASK_APP,在后面我们还会用到其他环境变量。环境变量在新创建命令行窗口或重启电脑后就清除了,每次都要重设变量有些麻烦。而且如果你同时开发多个 Flask 程序,这个 FLASK_APP 就需要在不同的值之间切换。为了避免频繁设置环境变量,我们可以使用 python-dotenv 管理项目的环境变量,首先使用 Pipenv 将它安装到虚拟环境:

$ pipenv install python-dotenv

我们在项目根目录下分别创建两个文件:.env 和.flaskenv。.flaskenv 用来存储和 Flask 相关的公开环境变量,比如 FLASK_APP;而.env 用来存储包含敏感信息的环境变量,比如后面我们会用来配置 Email 服务器的账户名与密码。在.flaskenv 或.env 文件中,环境变量使用键值对的形式定义,每行一个,以#开头的为注释,如下所示:

SOME_VAR=1
# 这是注释
FOO="BAR"

注意
.env 包含敏感信息,除非是私有项目,否则绝对不能提交到 Git 仓库中。当你开发一个新项目时,记得把它的名称添加到.gitignore 文件中,这会告诉 Git 忽略这个文件。gitignore 文件是一个名为.gitignore 的文本文件,它存储了项目中 Git 提交时的忽略文件规则清单。Python 项目的.gitignore 模板可以参考 https://github.com/github/gitignore/blob/master/Python.gitignore 。使用 PyCharm 编写程序时会产生一些配置文件,这些文件保存在项目根目录下的.idea 目录下,关于这些文件的忽略设置可以参考 https://www.gitignore.io/api/pycharm

3.使用 PyCharm 运行服务器

在 PyCharm 中,虽然我们可以使用内置的命令行窗口执行命令以启动开发服务器,但是在开发时使用 PyCharm 内置的运行功能更加方便。在 2018.1 版本后的专业版添加了 Flask 命令行支持,在旧版本或社区版中,如果要使用 PyCharm 运行程序,还需要进行一些设置。

首先,在 PyCharm 中,单击菜单栏中的 Run→Edit Configurations 打开运行配置窗口。图 1-6 中标出了在 PyCharm 中设置一个运行配置的具体步骤序号。

image.png
图 1-6 运行 Flask 程序的配置

打开新建配置窗口后,具体的步骤如下所示:

  • 步骤 1  单击左侧的“+”符号打开下拉列表。

  • 步骤 2  新建一个 Python 类型的运行配置(如果你使用的是专业版,则可以直接选择 Flask server),并在右侧的 Name 字段输入一个合适的名称,比如“Run hello”。

  • 步骤 3  勾选“Single instance only”。

  • 步骤 4  将第一项配置字段通过下列选项选为“Module Name”。

  • 步骤 5  填入模块名称 flask。

  • 步骤 6  第二栏的“Parameters”填入要执行的命令 run,你也可以附加其他启动选项。

  • 步骤 7  在“Working directory”字段中选择程序所在的目录作为工作目录。

提示
我们可以单击左上方的复制图标复制一份配置,然后稍加修改就可以用于其他 flask 命令,包括扩展提供的命令,或是我们自定义的命令。

现在单击 Apply 或 OK 保存并关闭窗口。在 PyCharm 右上方选择我们创建的运行配置,然后单击绿色三角形的运行按钮即可启动开发服务器。

注意
因为本章示例程序的模块名称为 app.py,Flask 会自动从中寻找程序实例,所以我们在 PyCharm 中的运行设置可以正确启动程序。如果你不打算使用 python-dotenv 来管理环境变量,那么需要修改 PyCharm 的运行配置:在 Enviroment variable 字段中添加环境变量 FLASK_APP 并设置正确的值。

2、更多的启动选项

1.使服务器外部可见

我们在上面启动的 Web 服务器默认是对外不可见的,可以在 run 命令后添加--host 选项将主机地址设为 0.0.0.0 使其对外可见:

$ flask run --host=0.0.0.0

这会让服务器监听所有外部请求。个人计算机(主机)一般没有公网 IP(公有地址),所以你的程序只能被局域网内的其他用户通过你的个人计算机的内网 IP(私有地址)访问,比如你的内网 IP 为 192.168.191.1。当局域网内的其他用户访问 http://192.168.191.1:5000 时,也会看到浏览器里显示一行“Hello,Flask!”。

提示
把程序安装在拥有公网 IP 的服务器上,让互联网上的所有人都可以访问是我们最后要介绍的程序部署部分的内容。如果你迫切地想把你的程序分享给朋友们,可以考虑使用 ngrok(https://ngrok.com/ )、Localtunnel(https://localtunnel.github.io/www/ )等内网穿透/端口转发工具。

2.改变默认端口

Flask 提供的 Web 服务器默认监听 5000 端口,你可以在启动时传入参数来改变它:

$ flask run --port=8000

这时服务器会监听来自 8000 端口的请求,程序的主页地址也相应变成了 http://localhost:8000/

附注
执行 flask run 命令时的 host 和 port 选项也可以通过环境变量 FLASK_RUN_HOST 和 FLASK_RUN_PORT 设置。事实上,Flask 内置的命令都可以使用这种模式定义默认选项值,即“FLASK__”,你可以使用 flask --help 命令查看所有可用的命令。

3、设置运行环境

开发环境(development enviroment)和生产环境(production enviroment)是我们后面会频繁接触到的概念。开发环境是指我们在本地编写和测试程序时的计算机环境,而生产环境与开发环境相对,它指的是网站部署上线供用户访问时的服务器环境。

根据运行环境的不同,Flask 程序、扩展以及其他程序会改变相应的行为和设置。为了区分程序运行环境,Flask 提供了一个 FLASK_ENV 环境变量用来设置环境,默认为 production(生产)。在开发时,我们可以将其设为 development(开发),这会开启所有支持开发的特性。为了方便管理,我们将把环境变量 FLASK_ENV 的值写入.flaskenv 文件中:

FLASK_ENV=development

现在启动程序,你会看到下面的输出提示:

$ flask run
 * Environment: development
 * Debug mode: on
 * Debugger is active!
 * Debugger PIN: 202-005-064
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
111

在开发环境下,调试模式(Debug Mode)将被开启,这时执行flask run启动程序会自动激活Werkzeug内置的调试器(debugger)和重载器(reloader),它们会为开发带来很大的帮助。

> 提示
如果你想单独控制调试模式的开关,可以通过FLASK_DEBUG环境变量设置,设为1则开启,设为0则关闭,不过通常不推荐手动设置这个值。

> 注意
在生产环境中部署程序时,绝不能开启调试模式。尽管PIN码可以避免用户任意执行代码,提高攻击者利用调试器的难度,但并不能确保调试器完全安全,会带来巨大的安全隐患。而且攻击者可能会通过调试信息获取你的数据库结构等容易带来安全问题的信息。另一方面,调试界面显示的错误信息也会让普通用户感到困惑。

### 1、调试器

Werkzeug提供的调试器非常强大,当程序出错时,我们可以在网页上看到详细的错误追踪信息,这在调试错误时非常有用。运行中的调试器如图1-7所示。
![image.png](https://b3logfile.com/file/2019/09/image-3a4a7371.png)

调试器允许你在错误页面上执行Python代码。单击错误信息右侧的命令行图标,会弹出窗口要求输入PIN码,也就是在启动服务器时命令行窗口打印出的调试器PIN码(Debugger PIN)。输入PIN码后,我们可以单击错误堆栈的某个节点右侧的命令行界面图标,这会打开一个包含代码执行上下文信息的Python Shell,我们可以利用它来进行调试。

### 2.重载器

当我们对代码做了修改后,期望的行为是这些改动立刻作用到程序上。重载器的作用就是监测文件变动,然后重新启动开发服务器。当我们修改了脚本内容并保存后,会在命令行看到下面的输出:

111
Detected change in '/path/to/app.py', reloading
 * Restarting with stat
111

默认会使用Werkzeug内置的stat重载器,它的缺点是耗电较严重,而且准确性一般。为了获得更优秀的体验,我们可以安装另一个用于监测文件变动的Python库Watchdog,安装后Werkzeug会自动使用它来监测文件变动:

$ pipenv install watchdog --dev


因为这个包只在开发时才会用到,所以我们在安装命令后添加了一个--dev选项,这用来把这个包声明为开发依赖。在Pipfile文件中,这个包会被添加到dev-packages部分。

不过,如果项目中使用了单独的CSS或JavaScript文件时,那么浏览器可能会缓存这些文件,从而导致对文件做出的修改不能立刻生效。在浏览器中,我们可以按下Crtl+F5或Shift+F5执行硬重载(hard reload),即忽略缓存并重载(刷新)页面。

> 提示
当在一个新电脑创建运行环境时,使用pipenv install命令时需要添加额外的--dev选项才会安装dev-packages部分定义的开发依赖包。

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...