使用 Heroku 部署 Python Flask 示例应用程序

举报
Yuchuan 发表于 2021/08/21 08:22:59 2021/08/21
【摘要】 恭喜,您现在已经知道如何使用 Flask 创建 Web 应用程序,以及如何通过使用 Heroku 部署来使其公开可用。您还知道如何设置不同的环境,让您、您的团队和您的客户可以在发布应用程序之前对其进行审核。虽然本教程中创建的示例应用程序非常小,但您可以将其用作下一个项目的起点!

目录

在本教程中,您将创建一个 Python Flask示例应用程序并使用Heroku部署它,使其在网络上公开可用。Heroku 消除了与构建和运行Web 应用程序相关的大部分基础设施负担,让您可以专注于创建出色的应用程序。

除了部署应用程序之外,您还将使用 Git 来跟踪代码更改,并且您还将使用不同的环境配置部署工作流以进行暂存和生产。使用此设置,您将能够在发布应用程序之前对其进行测试和预览。

在本教程中,您将学习如何:

  • 创建 Python Flask 示例 Web 应用程序
  • 使用 Heroku部署Web 应用程序
  • 使用 Heroku管道实现部署工作流
  • 以安全的方式管理不同环境的配置机密

本教程假设您了解 Web 应用程序如何工作的基础知识,并且您有一些使用 Git 的经验。要快速了解这些主题,请查看使用 Flask 的 Python Web 应用程序(教程系列)Python 开发人员的 Git 和 GitHub 简介

正如您将通过本教程了解到的,通过结合 Flask 和 Heroku,您可以最大限度地减少创建和运行 Web 应用程序所需的工作量。您可以单击下面的链接以获取本教程应用程序的完整源代码:

创建 Python Flask 示例应用程序

在本节中,您将学习如何创建 Python Flask 示例应用程序并在本地运行它。您将初始化项目、安装 Flask、创建应用程序并在您的计算机上运行它。您还将学习如何使用 Git 对应用程序代码进行版本控制。

初始化项目

项目初始化包括为您的应用程序创建一个目录、设置将安装依赖项的Python 虚拟环境以及初始化Git 存储库。您不必使用虚拟环境或 Git 进行本地开发,但它们非常方便,将使开发和部署到 Heroku 变得更简单。

首先为 Python Flask 示例应用程序创建一个新目录。您可以通过运行以下命令来完成:

$ mkdir realpython-example-app
$ cd realpython-example-app

上述命令创建一个realpython-example-app/文件夹并将当前工作目录更改为该文件夹。

接下来,您必须创建一个 Python 虚拟环境。使用虚拟环境可以让您管理项目的依赖项,而不会弄乱所有应用程序共享的系统级文件。运行以下命令为您的应用程序创建和激活虚拟环境。realpython-example-app/如果您还没有,请记住将目录更改为:

$ python3 -m venv venv
$ source venv/bin/activate

这些命令创建一个名为的虚拟环境venv并激活它,因此将从该环境加载和安装包,而不是使用系统级包。

安装依赖

第一步是安装 Flask Python 包。您可以运行以下命令来使用以下命令安装 Flask pip

$ python3 -m pip install Flask==1.1.2

上面的命令安装 Flask 版本1.1.2。这是您将在本教程中使用的版本。接下来,您需要创建一个requirements.txt列出项目依赖项的文件。您可以使用以下python3 -m pip freeze命令执行此任务:

$ python3 -m pip freeze > requirements.txt

您将requirements.txt在部署项目时使用来告诉 Heroku 必须安装哪些包才能运行您的应用程序代码。要了解有关如何在虚拟环境中安装 Flask 和其他pip选项的更多信息,请查看Flask 安装文档什么是 Pip?新 Pythonistas 指南

现在,应用程序目录应如下所示:

realpython-example-app/
│
├── venv/
│
└── requirements.txt

在以下部分中,您将添加更多文件来实现应用程序逻辑、设置 Git,然后将其部署到 Heroku。

编写应用程序代码

在本节中,您将创建一个带有单个路由的小型 Flask 应用程序, indexHello World!在请求时返回文本。要创建 Flask 应用程序,您必须创建一个Flask代表您的应用程序的对象,然后将视图与路由相关联。Flask 负责根据请求 URL 和您定义的路由将传入请求分派到正确的视图。

您可以单击下面的链接以获取本教程应用程序的完整源代码:

示例代码: 单击此处下载您将用于在本教程中构建 Python Flask 示例应用程序的源代码

对于小型应用程序,例如您在本教程中使用的应用程序,您可以将所有代码编写在一个文件中,并按如下方式组织您的项目:

realpython-example-app/
│
├── venv/
│
├── app.py
└── requirements.txt

app.py包含应用程序的代码,您可以在其中创建应用程序及其视图。以下代码块显示了应用程序的完整源代码:

from flask import Flask

app = Flask(__name__)

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

你之后导入 flask,代码创建对象app,属于Flask类。视图函数index()使用app.route() 装饰器链接到主路由。当请求主路由时,Flask 将通过调用index()并使用其返回值作为响应来服务请求。

在本地运行 Python Flask 示例

您可以通过多种方式运行在上一节中创建的应用程序。为本地开发启动 Flask 应用程序的最直接方法之一是使用flask run终端中的命令:

$ flask run

默认情况下,Flask 将运行您在app.py端口上定义的应用程序5000。在应用程序运行时,转到http://localhost:5000使用 Web 浏览器。您将看到一个包含该消息的网页Hello World!

在开发过程中,您通常希望在对应用程序进行更改时自动重新加载它。您可以通过将环境变量 , 传递FLASK_ENV=developmentflask run

$ FLASK_ENV=development flask run

当您设置 时FLASK_ENV=development,Flask 将监视对应用程序文件的更改并在发生更改时重新加载服务器。这样,您无需在每次修改后手动停止和重新启动应用服务器。

使用 Git 跟踪更改

在本教程中,您将使用 Git(一种非常流行的版本控制系统 (VCS))跟踪对项目文件的更改。因此,作为第一步,您应该为您的项目创建一个 Git 存储库。您可以通过在项目目录中执行以下命令来实现此目的:

$ git init

上述命令初始化将用于跟踪项目文件的存储库。存储库元数据存储在名为 的隐藏目录中.git/

请注意,有些文件夹不应包含在 Git 存储库中,例如venv/__pycache__/。您可以通过创建一个名为 .git 的文件来告诉 Git 忽略它们.gitignore。使用以下命令创建此文件:

$ echo venv > .gitignore
$ echo __pycache__ >> .gitignore
$ git add .gitignore app.py requirements.txt
$ git commit -m "Initialize Git repository"

运行上述命令后,Git 将跟踪对应用程序文件的更改,但会忽略venv/__pycache__/文件夹。现在,项目目录realpython-example-app/应如下所示:

realpython-example-app/
│
├── .git/
│
├── venv/
│
├── .gitignore
├── app.py
└── requirements.txt

您现在已准备好使用 Heroku 部署您的应用程序。查看Python 开发人员的 Git 和 GitHub 简介,了解有关 Git 以及如何在 GitHub 中托管存储库的更多信息。

将应用程序部署到 Heroku

Heroku 使构建和部署应用程序对开发人员非常友好。它消除了与构建和运行 Web 应用程序相关的大部分负担,处理大多数基础架构细节,让您专注于创建和改进应用程序。Heroku 处理的一些细节包括:

  • 配置 HTTPS 证书
  • 管理 DNS 记录
  • 运行和维护服务器

在本节的其余部分,您将学习如何使用 Heroku 将先前创建的 Web 应用程序部署到 Internet。到本节结束时,您的应用程序将在一个不错的 URL 下公开可用,并使用HTTPS 提供服务

Heroku 帐户设置

您的第一步是创建一个 Heroku 帐户。如果您还没有,您可以使用免费和业余爱好计划。它允许您在不花钱的情况下部署非商业应用程序、个人项目和实验。

如果您转到Heroku 注册页面,您将在注册表单上看到以下字段:

Heroku 注册屏幕

完成所需信息并确认您的电子邮件地址后,您就可以开始使用 Heroku。

Heroku 命令行界面 (CLI)

Heroku 命令行界面 (CLI) 是一种允许您从终端创建和管理 Heroku 应用程序的工具。这是部署应用程序的最快捷、最方便的方式。您可以查看开发人员的文档以获取操作系统的安装说明。在大多数 Linux 发行版上,您可以通过运行以下命令来安装 Heroku CLI:

$ curl https://cli-assets.heroku.com/install.sh | sh

前面的命令下载 Heroku CLI 安装程序并执行它。接下来,您必须通过运行以下命令登录:

$ heroku login

这将打开一个带有按钮的网站以完成登录过程。单击登录以完成身份验证过程并开始使用 Heroku CLI:

Heroku 登录屏幕

登录后,您就可以开始使用 Heroku CLI 来管理您的应用程序和工作流了。

应用程序部署到 Heroku

在本节中,您将学习如何使用 Heroku CLI 和 Git 部署您的 Web 应用程序。第一步是Procfile在项目的根目录中创建一个名为的文件。这个文件告诉 Heroku 如何运行应用程序。您可以通过运行以下命令来创建它:

$ echo "web: gunicorn app:app" > Procfile

请注意,此文件名必须以大写字母开头。该文件告诉 Heroku 使用Gunicorn为您的应用程序提供服务,这是一种 Python Web 服务器网关接口 (WSGI) HTTP 服务器,与各种 Web 框架(包括 Flask 兼容。确保安装 Gunicorn 并requirements.txt使用pip以下命令更新文件:

$ python3 -m pip install gunicorn==20.0.4
$ python3 -m pip freeze > requirements.txt

前面的命令安装 Gunicorn 并更新requirements.txt以包含所有依赖项的列表。由于您添加和更改了文件,因此您需要将它们提交到 Git。您可以通过执行以下两个命令来做到这一点:

$ git add Procfile requirements.txt
$ git commit -m "Add Heroku deployment files"

当您执行上述命令时,您将提交最新版本的Procfilerequirements.txt到 Git 存储库。现在您已准备好将应用程序部署到 Heroku。首先使用 Heroku CLI创建 Heroku 应用程序

注意:本教程使用realpython-example-app作为应用程序名称。由于应用程序名称在 Heroku 上必须是唯一的,因此您需要为部署选择不同的名称。

您可以通过运行以下命令在 Heroku 中创建应用程序:

$ heroku create realpython-example-app

运行上述命令初始化的Heroku应用程序,创建一个GIT中远程命名heroku。接下来,您可以将 Git 存储库推送到此远程以触发构建和部署过程:

$ git push heroku master

master分支推送到heroku远程后,您将看到输出显示有关构建和部署过程的信息:

Enumerating objects: 6, done.
 2Counting objects: 100% (6/6), done.
 3Delta compression using up to 8 threads
 4Compressing objects: 100% (4/4), done.
 5Writing objects: 100% (6/6), 558 bytes | 558.00 KiB/s, done.
 6Total 6 (delta 0), reused 0 (delta 0)
 7remote: Compressing source files... done.
 8remote: Building source:
 9remote:
10remote: -----> Building on the Heroku-18 stack
11remote: -----> Python app detected
12remote: -----> Installing python-3.6.12
13remote: -----> Installing pip 20.1.1, setuptools 47.1.1 and wheel 0.34.2
14remote: -----> Installing SQLite3
15remote: -----> Installing requirements with pip
16remote:        Collecting click==7.1.2
17remote:          Downloading click-7.1.2-py2.py3-none-any.whl (82 kB)
18remote:        Collecting Flask==1.1.2
19remote:          Downloading Flask-1.1.2-py2.py3-none-any.whl (94 kB)
20remote:        Collecting itsdangerous==1.1.0
21remote:          Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)
22remote:        Collecting Jinja2==2.11.2
23remote:          Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB)
24remote:        Collecting MarkupSafe==1.1.1
25remote:          Downloading MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl
26remote:        Collecting Werkzeug==1.0.1
27remote:          Downloading Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB)
28remote:        Installing collected packages: click, Werkzeug, itsdangerous,
29MarkupSafe, Jinja2, Flask
30remote:        Successfully installed Flask-1.1.2 Jinja2-2.11.2 MarkupSafe-1.1.1
31Werkzeug-1.0.1 click-7.1.2 itsdangerous-1.1.0
32remote: -----> Discovering process types
33remote:        Procfile declares types -> (none)
34remote:
35remote: -----> Compressing...
36remote:        Done: 45.1M
37remote: -----> Launching...
38remote:        Released v1
39remote:        https://realpython-example-app.herokuapp.com/ deployed to Heroku
40remote:
41remote: Verifying deploy... done.
42To https://git.heroku.com/realpython-example-app.git
43 * [new branch]      master -> master

恭喜,该应用程序现已上线!输出显示了构建过程,包括依赖项的安装和部署。在第 39 行,您将找到应用程序的 URL。在这种情况下,它是https://realpython-example-app.herokuapp.com/. 您还可以使用以下 Heroku CLI 命令打开应用程序的 URL:

$ heroku open

上面的命令将使用您的默认 Web 浏览器打开您的应用程序。

注意:输出的第 12 行表明 Python 3.6.12 将用作应用程序的运行时。这是编写本教程时的默认版本。要了解如何自定义 Python 版本和其他运行时设置,请查看Heroku 的 Python 运行时文档

现在让我们对应用程序进行一些小的更改,看看如何重新部署它。编辑app.py和修改返回的字符串index(),如下一个代码块所示:

from flask import Flask
 2
 3app = Flask(__name__)
 4
 5@app.route("/")
 6def index():
 7    return "Hello this is the new version!"

正如你在第 7 行看到的,"Hello World!"被替换为"Hello this is the new version!"You can deploy this version to Heroku by committing and push the changes to the herokuremote:

$ git add app.py
$ git commit -m "Change the welcome message"
$ git push heroku master

使用这些命令,您将更改提交到本地 Git 存储库并将它们推送到heroku远程。这将再次触发构建和部署过程。您可以在需要部署应用程序的新版本时重复这些步骤。您会注意到后续部署通常花费的时间更少,因为需求已经安装。

在本节中,您学习了如何使用 Git 和 Heroku CLI 在 Heroku 上创建和部署应用程序。有关使用 Heroku CLI 部署 Python 应用程序的更多详细信息,请查看使用 Python 开始使用 Heroku

使用 Heroku 管道实现部署工作流

在本节中,您将学习如何使用Heroku 管道为您的应用程序部署实现工作流。这个特定的工作流使用三个独立的环境,称为本地暂存生产。这种设置在专业项目中被广泛使用,因为它允许在将新版本部署到生产环境并将其展示给真实用户之前对其进行测试和审查。

了解部署工作流程

正如您在上面看到的,当您使用此工作流时,您将在三个独立的环境中运行应用程序:

  1. 发展是当地的环境。
  2. Staging是用于预览和测试的预生产环境。
  3. 生产是最终用户访问的实时站点。

在前面的部分中,您看到了如何在本地环境和 Heroku 的生产环境中运行应用程序。添加临时环境可以极大地有益于开发过程。此环境的主要目的是集成所有新分支的更改,并针对将成为下一个版本的构建运行集成测试。

接下来,您将看到如何在Heroku上创建临时环境,以及如何创建一个管道,以促进从登台到生产的版本。下图显示了此工作流程:

部署工作流图

上图显示了三个环境、在每个环境中发生的活动以及部署和升级步骤。

在 Heroku 中实现部署工作流

在 Heroku 中实现工作流包括两个步骤:

  1. 为登台和生产创建单独的应用程序
  2. 使两个应用程序成为同一管道的一部分

Heroku的管道是一组由工作流捆绑在一起的应用程序。这些应用程序中的每一个都是开发工作流程中的一个环境,如登台或生产。使用管道可确保在升级后,生产将运行您在暂存时查看的完全相同的代码。

在本教程中,之前创建的 Heroku 应用程序realpython-example-app用作生产环境。您应该使用以下命令为暂存环境创建一个新的 Heroku 应用程序:

$ heroku create realpython-example-app-staging --remote staging
$ git push staging master

运行这些命令会创建一个新的 Heroku 应用realpython-example-app-staging程序,并使用 Git 将应用程序部署到它。然后,您可以在 访问登台应用程序https://realpython-example-app-staging.herokuapp.com/。请注意,名为的 Git 远程staging与此应用程序相关联。

现在您拥有用于生产和登台的 Heroku 应用程序,您已准备好创建将它们链接在一起的 Heroku 管道。您可以使用 Heroku CLI 创建管道:

$ heroku pipelines:create --app realpython-example-app \
    --stage production \
    realpython-example-app
Creating realpython-example-app pipeline... done
Adding ⬢ realpython-example-app to realpython-example-app pipeline as production
... done

上面的命令创建一个名为管道realpython-example-app并添加名为realpython-example-app生产环境的应用程序。接下来,运行以下命令以创建指向此应用程序的 Git 远程,并将其命名为prod

$ heroku git:remote --app realpython-example-app --remote prod

从现在开始,您可以将生产部署称为prod.

接下来,通过运行以下命令将暂存应用程序添加到同一管道:

$ heroku pipelines:add realpython-example-app \
  --app realpython-example-app-staging \
  --stage staging
Adding ⬢ realpython-example-app-staging to realpython-example-app pipeline as
staging... done

此命令将应用程序添加realpython-example-app-staging到同一管道并指定此应用程序必须用于staging舞台。这意味着您的管道现在包含两个应用程序:

  1. realpython-example-app
  2. realpython-example-app-staging

第一个用作生产环境,第二个用作登台环境。

部署和升级到登台和生产

现在您已经配置了您的应用程序和管道,您可以使用它来将您的应用程序部署到暂存区,在那里进行审查,然后将其提升到生产环境。

例如,假设您想再次更改index()视图返回的消息。在这种情况下,您必须编辑app.py和更改index(). 以下代码块显示了新版本:

 1from flask import Flask
 2
 3app = Flask(__name__)
 4
 5@app.route("/")
 6def index():
 7    return "This is yet another version!"

正如您在第 7 行看到的,index()返回"This is yet another version!"您可以通过运行以下命令将此新版本部署到您的登台环境:

$ git add app.py
$ git commit -m "Another change to the welcome message"
$ git push staging master

这些命令提交app.py并将更改推送到staging远程,触发此环境的构建和部署过程。您应该会看到部署在 的新版本https://realpython-example-app-staging.herokuapp.com/。注意生产环境还在使用之前的版本。

当您对更改感到满意时,您可以使用 Heroku CLI 将新版本提升到生产环境:

$ heroku pipelines:promote --remote staging

上面的命令将当前在暂存中运行的完全相同的版本部署到生产中。您会注意到,在这种情况下,没有构建步骤,因为使用了来自暂存的相同构建并将其部署到生产中。您可以验证https://realpython-example-app.herokuapp.com/应用程序是否已升级并且它运行的是最新版本。

在本节中,您了解了部署工作流并在 Heroku 中实现了它。要了解有关使用管道和更高级工作流的更多信息,请查看Heroku 管道文档

管理不同环境的设置和Secrets

大多数应用程序需要针对每个环境进行不同的设置来执行诸如启用调试功能或指向其他数据库之类的操作。其中一些设置(如身份验证凭据数据库密码API 密钥)非常敏感,因此您必须避免将它们硬编码到应用程序文件中。

您可以创建一个config.py文件来保存非敏感配置值并从环境变量中读取敏感配置值。在以下代码块中,您可以看到 的源代码config.py

import os
 2
 3class Config:
 4    DEBUG = False
 5    DEVELOPMENT = False
 6    SECRET_KEY = os.getenv("SECRET_KEY", "this-is-the-default-key")
 7
 8class ProductionConfig(Config):
 9    pass
10
11class StagingConfig(Config):
12    DEBUG = True
13
14class DevelopmentConfig(Config):
15    DEBUG = True
16    DEVELOPMENT = True

此代码声明了一个Config类,用作每个环境配置的基础。请注意,在第 6 行,SECRET_KEY是使用os.getenv(). 这避免了在源代码中泄露实际密钥。同时,您可以为每个环境自定义任何选项。

接下来,您必须app.py根据环境进行修改以使用不同的配置类。这是完整的源代码app.py

 1import os
 2from flask import Flask
 3
 4app = Flask(__name__)
 5env_config = os.getenv("APP_SETTINGS", "config.DevelopmentConfig")
 6app.config.from_object(env_config)
 7
 8@app.route("/")
 9def index():
10    secret_key = app.config.get("SECRET_KEY")
11    return f"The configured secret key is {secret_key}."

在第 5 行和第 6 行,配置是从config.py. 具体的配置类将取决于存储在APP_SETTINGS环境变量中的值。如果变量未定义,则配置将回退到DevelopmentConfig默认值。

注意:对于这个例子,第 11 行的消息被修改为显示SECRET_KEYapp.config.get(). 您通常不会在回复中显示敏感信息。这只是展示如何读取这些值的示例。

现在您可以通过在启动应用程序时传递一些环境变量来查看它在本地是如何工作的:

$ SECRET_KEY=key-read-from-env-var flask run

上述命令设置SECRET_KEY环境变量并启动应用程序。如果您导航到http://localhost:5000,那么您应该会看到该消息The configured secret key is key-read-from-env-var

接下来,通过运行以下命令提交更改并将它们推送到暂存环境:

$ git add app.py config.py
$ git commit -m "Add config support"
$ git push staging master

这些命令将更改app.py和新config.py文件提交到本地 Git 存储库,然后将它们推送到暂存环境,这会触发新的构建和部署过程。在继续之前,您可以使用 Heroku CLI 为此环境自定义环境变量:

$ heroku config:set --remote staging \
  SECRET_KEY=the-staging-key \
  APP_SETTINGS=config.StagingConfig

使用该config:set命令,您已经为暂存设置了SECRET_KEY和的值APP_SETTINGS。您可以通过转到https://realpython-example-app-staging.herokuapp.com/并检查页面是否显示消息来验证更改是否已部署The configured secret key is the-staging-key

使用 Heroku CLI,您还可以获得任何应用程序的环境变量值。以下命令从 Heroku 获取为暂存环境设置的所有环境变量:

$ heroku config --remote staging
=== realpython-example-app-staging Config Vars
APP_SETTINGS: config.StagingConfig
SECRET_KEY:   the-staging-key

如您所见,这些值与之前设置的值相匹配。

最后,您可以使用 Heroku CLI 使用不同的配置值将新版本提升到生产环境:

$ heroku config:set --remote prod \
  SECRET_KEY=the-production-key \
  APP_SETTINGS=config.ProductionConfig
$ heroku pipelines:promote --remote staging

第一条命令设置值SECRET_KEY,并APP_SETTINGS为生产环境。第二个命令提升新的应用程序版本,即具有该config.py文件的版本。同样,您可以通过转到https://realpython-example-app.herokuapp.com/并检查页面是否显示来验证更改是否已部署The configured secret key is the-production-key

在本节中,您学习了如何为每个环境使用不同的配置以及如何使用环境变量处理敏感设置。请记住,在实际应用程序中,您不应公开诸如SECRET_KEY.

结论

恭喜,您现在已经知道如何使用 Flask 创建 Web 应用程序,以及如何通过使用 Heroku 部署来使其公开可用。您还知道如何设置不同的环境,让您、您的团队和您的客户可以在发布应用程序之前对其进行审核。虽然本教程中创建的示例应用程序非常小,但您可以将其用作下一个项目的起点!

在本教程中,您学习了如何:

  • 创建 Python Flask 示例 Web 应用程序
  • 使用Heroku部署 Web 应用程序
  • 使用 Heroku管道实现部署工作流
  • 以安全的方式管理不同环境的配置和机密

Heroku 提供了许多前几节未涵盖的功能,包括扩展、数据库等。查看Heroku 开发中心Heroku 平台文档,了解可帮助您加速开发的其他功能。最后,查看Flask by Example教程系列,了解如何创建和部署更复杂的应用程序。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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