Heroku 使用教程

Heroku平臺


Heroku平臺的靈活性極高且支持多種編程語言。若想把程序部署到Heroku上,開發(fā)者要使用Git把程序推送到HerokuGit服務器上。在服務器上,git push命令會自動觸發(fā)安裝、配置和部署程序。

Heroku使用名為Dyno的計算單元衡量用量,并以此為依據(jù)收取服務費用。最常用的Dyno類型是Web Dyno,表示一個Web服務器實例。程序可以通過使用更多的Web Dyno以增強其請求處理能力。另一種Dyno類型是Worker Dyno,用來執(zhí)行后臺作業(yè)或其他輔助任務。

Heroku提供了大量的插件和擴展,可用于數(shù)據(jù)庫、電子郵件支持和其他很多服務。

準備程序


若想使用 Heroku,程序必須托管在 Git 倉庫中。如果你的程序托管在像 GitHub 或 BitBucket 這樣的遠程 Git 服務器上,那么在本地 clone 程序后會創(chuàng)建一個本地 Git 倉庫,可無縫用于 Heroku。如果你的程序沒有托管在 Git 倉庫中,那么必須在開發(fā)電腦上創(chuàng)建一個倉庫。

注冊Heroku賬戶


heroku 官網(wǎng)

安裝Heroku Toolbelt


Heroku Toolbelt

Heroku Toolbelt是用于創(chuàng)建、管理Herokuapps的命令行工具

heroku 的命令行客戶端將被安裝到/usr/local/heroku,同時,/usr/local/heroku/bin將被添加到你的PATH環(huán)境變量

下載并安裝完成后,在 shell 中輸入heroku login,用創(chuàng)建heroku賬號的email密碼登陸

$ heroku login
Enter your Heroku credentials.
Email: adam@example.com
Password (typing will be hidden):
Authentication successful.

把你的 SSH 公鑰上傳到 Heroku,這一點很重要,上傳后才能使用 git push 命令。正常情況下,login 命令會自動創(chuàng)建并上傳 SSH 公鑰。

創(chuàng)建程序


首先要確保程序在 Git 源碼控制系統(tǒng)中,然后在程序的頂級目錄下運行創(chuàng)建命令

在 Heroku 創(chuàng)建一個 app, 以便 Heroku 準備好接收你的代碼

當你創(chuàng)建一個 app, 將創(chuàng)建并關聯(lián)一個名為heroku的遠端到你的本地倉庫

apps:create [NAME] # create a new app 名稱必須以字母開始,只能包含小寫字母,數(shù)字和連字符, 而且名稱在 heroku 的所有程序中必須是唯一的

?  flask_blog git:(rest) ? heroku apps:create flask-blog-chaonet
Creating flask-blog-chaonet... done, stack is cedar-14
https://flask-blog-chaonet.herokuapp.com/ | https://git.heroku.com/flask-blog-chaonet.git
Git remote heroku added

查看已創(chuàng)建的 app

?  flask_blog git:(rest) ? heroku apps
=== My Apps
flask-blog-chaonet

默認 Heroku 會為你的 app 生成一個隨機的名字, 或者 你可以通過可選參數(shù)指定你的 app名。

現(xiàn)在,你可以向 Heroku 部署你的代碼了

$ git push heroku master # 必須將 本地 的 master push 到 heroku 的 master

應用現(xiàn)在已經(jīng)部署了,確保至少一個 app 的實例正在運行:

$ heroku ps:scale web=1

現(xiàn)在,可以用創(chuàng)建的包含 app 名稱的 URL 訪問 app. 有一個便捷的方法, 你可以像這樣打開web站點:

$ heroku open

配置數(shù)據(jù)庫


Heroku 以擴展形式支持 Postgres 數(shù)據(jù)庫。少于 1 萬條記錄、同時連接數(shù) 20 、沒有緩存 、不允許fork/follow、沒有 Postgres 日志 的小型數(shù)據(jù)庫無需付費即可添加 到程序中。

官網(wǎng)教程: heroku-postgresql

添加 Postgres 到 Heroku 應用

通過命令行,將 Heroku Postgres 添加到一個 Heroku 應用:

?  flask_blog git:(rest) ? heroku addons:create heroku-postgresql:hobby-dev
Creating postgresql-sinuous-8326... done, (free)
Adding postgresql-sinuous-8326 to flask-blog-chaonet... done
Setting DATABASE_URL and restarting flask-blog-chaonet... done, v3
Database has been created and is available
 ! This database is empty. If upgrading, you can transfer
 ! data from another database with pg:copy
Use `heroku addons:docs heroku-postgresql` to view documentation.

選擇正確的 Heroku Postgres 方案

heroku-postgresql 插件

最低等級的業(yè)余版本有兩種方案 hobby-dev 和 hobby-basic

一旦 Heroku Postgres 被添加,一個 DATABASE_URL 設置將在 app 配置中生效,并包含用于訪問新提供的 Heroku Postgres 服務的 URL 。

這可以使用 heroku config 命令確認:

?  flask_blog git:(rest) ? heroku config -s | grep DATABASE_URL
DATABASE_URL=postgres://bjtrukgnhvnban:T0_N_OWYVz6NnasUwOf0FxVscO@ec2-54-83-52-71.compute-1.amazonaws.com:5432/d44ph8k76dl0h0

amazonaws ?

  • 建立主數(shù)據(jù)庫

Heroku 中的每個程序都支持多個數(shù)據(jù)庫。Heroku 建議使用 DATABASE_URL 變量保存主用數(shù)據(jù)庫信息。在單個數(shù)據(jù)庫的情況下,新的數(shù)據(jù)庫已經(jīng)被指定到 DATABASE_URL 。

對于多個數(shù)據(jù)庫的情況,可以設置主用數(shù)據(jù)庫:

$ heroku pg:promote HEROKU_POSTGRESQL_RED
Promoting HEROKU_POSTGRESQL_RED_URL to DATABASE_URL... done

DATABASE_URL 環(huán)境變量的格式正是 SQLAlchemy 所需的。回想一下 config.py 腳本的內(nèi)容,如果 設定了 DATABASE_URL,就使用其中保存的值,所以現(xiàn)在程序可以自動連接到 Postgres 數(shù)據(jù)庫。

  • 查看數(shù)據(jù)庫使用信息
?  flask_blog git:(rest) ? heroku pg:info
=== DATABASE_URL
Plan:        Hobby-dev
Status:      Available
Connections: 0/20
PG Version:  9.4.5
Created:     2016-01-09 02:57 UTC
Data Size:   6.7 MB
Tables:      0
Rows:        0/10000 (In compliance)
Fork/Follow: Unsupported
Rollback:    Unsupported
Add-on:      postgresql-sinuous-8326

heroku 的命令行命令

在 MAC 中安裝 Postgres

推薦在本地開發(fā)環(huán)境與生產(chǎn)環(huán)境運行相同的數(shù)據(jù)庫

使用Postgres.app,是在 Mac 下使用PostgreSQL的最簡單的方法

postgresapp下載Postgres.app
解壓后將Postgres移到應用程序文件夾
雙擊,然后你的 MAC 中就有一個PostgreSQL服務器在運行了

  • 使用 Postgres.app 的命令行工具

配置$PATH變量

?  psycopg2-2.6.1  which psql
psql not found
?  psycopg2-2.6.1  export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/latest/bin
?  psycopg2-2.6.1  which psql
/Applications/Postgres.app/Contents/Versions/latest/bin/psql

通過命令psql連接你的數(shù)據(jù)庫

?  psycopg2-2.6.1  psql -h localhost
psql (9.5.0)
Type "help" for help.

chao-# \q
?  psycopg2-2.6.1

Using Command Line Tools with Postgres.app

在本地安裝 Heroku Postgres

與 Python 對接

官網(wǎng)教程

?  psycopg2-2.6.1  pip install psycopg2
Collecting psycopg2
  Using cached psycopg2-2.6.1.tar.gz
Building wheels for collected packages: psycopg2
  Running setup.py bdist_wheel for psycopg2
  Stored in directory: /Users/chao/Library/Caches/pip/wheels/e2/9a/5e/7b620848bbc7cfb9084aafea077be11618c2b5067bd532f329
Successfully built psycopg2
Installing collected packages: psycopg2
Successfully installed psycopg2-2.6.1

遇到的問題:

沒有通過 postgres.app 安裝 Postgres,就安裝 psycopg2 ,結果報錯

  • pip 安裝
?  flask_blog git:(rest) ? pip install psycopg2
Collecting psycopg2
  Using cached psycopg2-2.6.1.tar.gz
    Complete output from command python setup.py egg_info:
    running egg_info
    creating pip-egg-info/psycopg2.egg-info
    writing pip-egg-info/psycopg2.egg-info/PKG-INFO
    writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt
    writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt
    writing manifest file 'pip-egg-info/psycopg2.egg-info/SOURCES.txt'
    warning: manifest_maker: standard file '-c' not found

    Error: pg_config executable not found.

    Please add the directory containing pg_config to the PATH
    or specify the full executable path with the option:

        python setup.py build_ext --pg-config /path/to/pg_config build ...

    or with the pg_config option in 'setup.cfg'.

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/36/tdbs35wx1sx4d6nm4hrmwy0h0000gn/T/pip-build-XR5kDF/psycopg2

  • 下載安裝包安裝
?  psycopg2-2.6.1  ls
AUTHORS     LICENSE     MANIFEST.in NEWS        README.rst  examples    psycopg     setup.cfg   tests
INSTALL     MANIFEST    Makefile    PKG-INFO    doc         lib         scripts     setup.py

?  psycopg2-2.6.1  python setup.py build
running build
running build_py
creating build
creating build/lib.macosx-10.6-intel-2.7
creating build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/__init__.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/_json.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/_range.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/errorcodes.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/extensions.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/extras.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/pool.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/psycopg1.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
copying lib/tz.py -> build/lib.macosx-10.6-intel-2.7/psycopg2
creating build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/__init__.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/dbapi20.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/dbapi20_tpc.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_async.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_bug_gc.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_bugX000.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_cancel.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_connection.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_copy.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_cursor.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_dates.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_extras_dictcursor.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_green.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_lobject.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_module.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_notify.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_psycopg2_dbapi20.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_quote.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_transaction.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_types_basic.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_types_extras.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/test_with.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/testconfig.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
copying tests/testutils.py -> build/lib.macosx-10.6-intel-2.7/psycopg2/tests
running build_ext
Error: pg_config executable not found.

Please add the directory containing pg_config to the PATH
or specify the full executable path with the option:

    python setup.py build_ext --pg-config /path/to/pg_config build ...

or with the pg_config option in 'setup.cfg'.
?  psycopg2-2.6.1

配置 Python 用于 Postgres.app

在 Flask 中使用 Flask-SQLAlchemy 擴展時,可以直接在配置中定義,并由 app 讀取。

Postgres.app 的配置文檔

配置日志


任何寫到 標準輸出(stdout) 或標準錯誤(stderr) 的信息才會被 Heroku 抓取到日志,并在 Heroku 客戶端通過heroku logs命令查看。

config.py

        # 輸出到 stderr,以便被 Heroku 抓取到 logs
        import logging
        from logging import StreamHandler
        file_handler = StreamHandler()
        file_handler.setLevel(logging.WARNING)
        app.logger.addHandler(file_handler)

定義配置變量


Heroku 可以讓你在程序外部配置變量 —— 存儲類似加密密鑰外部資源地址的數(shù)據(jù)。

在運行時, 配置的變量被當做環(huán)境變量暴露給應用。

變量可以用Heroku的命令行工具配置,也可以在應用的Dashboard頁面的settings頁簽下配置。

官網(wǎng)資料

配置電子郵件


Heroku 沒有提供 SMTP 服務器,所以我們要配置一個外部服務器。很多第三方擴展能把 適用于生產(chǎn)環(huán)境的郵件發(fā)送服務集成到 Heroku 中,但對于測試和評估而言,使用繼承自 Config 基類的 mail 配置已經(jīng)足夠了。

由于直接把安全密令寫入腳本存在安全隱患,所以我們把訪問 mail SMTP服務器的用戶 名和密碼保存在環(huán)境變量中。

運行生產(chǎn) Web 服務器


Heroku 沒有為托管程序提供 Web 服務器,相反,它希望程序啟動自己的服務器并監(jiān)聽環(huán) 境變量 PORT 中設定的端口。

Flask 自帶的開發(fā) Web 服務器表現(xiàn)很差,因為它不是為生產(chǎn)環(huán)境設計的服務器。有兩個 可以在生產(chǎn)環(huán)境中使用、性能良好且支持 Flask 程序的服務器,分別是GunicornuWSGI

若想在本地測試 Heroku 配置,我們最好在虛擬環(huán)境中安裝 Web 服務器。例如,可通過如下命令安裝 Gunicorn:

(venv) $ pip install gunicorn

若要使用 Gunicorn 運行程序,可執(zhí)行下面的命令:

     (venv) $ gunicorn manage:app
     2013-12-03 09:52:10 [14363] [INFO] Starting gunicorn 18.0
     2013-12-03 09:52:10 [14363] [INFO] Listening at: http://127.0.0.1:8000 (14363)
     2013-12-03 09:52:10 [14363] [INFO] Using worker: sync
     2013-12-03 09:52:10 [14368] [INFO] Booting worker with pid: 14368

manage:app 參數(shù)冒號左邊的部分表示定義程序的包或者模塊,冒號右邊的部分表示包中程序?qū)嵗拿?/code>。注意,Gunicor 默認使用端口 8000,而 Flask 默認使用 5000

添加依賴需求文件


Heroku 從程序頂級文件夾下的 requirements.txt 文件中加載包依賴。這個文件中的所有依賴都會在部署過程中導入 Heroku 創(chuàng)建的虛擬環(huán)境。

Heroku 的需求文件必須包含程序在生產(chǎn)環(huán)境中使用的所有通用依賴,以及支持 Postgres 數(shù)據(jù)庫的 psycopg2 包和 Gunicorn Web 服務器。

可以在需求文件中導入需求文件。

requirements.txt

     -r requirements/prod.txt
     gunicorn==18.0
     psycopg2==2.5.1

添加Procfile文件


Heroku 需要知道使用哪個命令啟動程序。命令在一個名為Procfile(沒有后綴)的特殊文件中指定。這個文件必須放在程序的頂級文件夾中。

web: gunicorn manage:app

Procfile文件內(nèi)容的格式很簡單:在每一行中指定一個任務名,后跟一個冒號,然后是執(zhí)行這個任務的命令。名為web的任務比較特殊任務,Heroku 使用這個任務啟動 Web 服務器。

Heroku 會為這個任務提供一個PORT環(huán)境變量,用于設定程序監(jiān)聽請求的端口。如果設定了PORT變量, Gunicorn默認就會使用其中保存的值,因此無需將其包含在啟動命令中。

部署程序后,Heroku 會運行 Procfile 中列出的所有任務。

任務格式模板

程序可在 Procfile 中使用 web 之外的名字聲明其他任務,例如程序所需的其他服務。

聲明任務類型的方式

使用 Heroku Local 進行本地測試


官方教程

Heroku Local作為Heroku Toolbelt的一部分, 自動被安裝。

  • 在本地啟動所有在你的Profile中定義的任務

$ heroku local

heroku localheroku local:start的簡寫,作用相同

?  flask_blog git:(rest) ? heroku local
Downloading forego-0.16.1 to /Users/chao/.heroku... done
forego | starting web.1 on port 5000
web.1  | [2016-01-10 00:11:00 +0800] [17093] [INFO] Starting gunicorn 19.4.5
web.1  | [2016-01-10 00:11:00 +0800] [17093] [INFO] Listening at: http://0.0.0.0:5000 (17093)
web.1  | [2016-01-10 00:11:00 +0800] [17093] [INFO] Using worker: sync
web.1  | [2016-01-10 00:11:00 +0800] [17096] [INFO] Booting worker with pid: 17096

指定運行的端口

?  flask_blog git:(rest) ? heroku local -p 8000
forego | starting web.1 on port 8000
web.1  | [2016-01-10 00:20:22 +0800] [17237] [INFO] Starting gunicorn 19.4.5
web.1  | [2016-01-10 00:20:22 +0800] [17237] [INFO] Listening at: http://0.0.0.0:8000 (17237)
web.1  | [2016-01-10 00:20:22 +0800] [17237] [INFO] Using worker: sync
web.1  | [2016-01-10 00:20:22 +0800] [17240] [INFO] Booting worker with pid: 17240
web.1  | [2016-01-10 00:21:11 +0800] [17237] [CRITICAL] WORKER TIMEOUT (pid:17240)
web.1  | [2016-01-10 00:21:11 +0800] [17240] [INFO] Worker exiting (pid: 17240)
web.1  | [2016-01-10 00:21:11 +0800] [17244] [INFO] Booting worker with pid: 17244

可以在本地指定運行一個特定的進程類型,例如webworker

$ heroku local web

然后,你就可以在本地測試 app。使用Ctrl+C停止

  • 設置本地環(huán)境變量

在本地運行 APP,同樣需要輸入一系列 配置變量 作為 app 的配置。.env文件讓你可以收集 app 在本地運行所需要的配置變量。當使用heroku local命令運行 APP,將會讀取.env文件,并且,每一個 名稱/值 對會被插入環(huán)境中,模仿實際的配置變量。

增加一個配置變量到你的.env文件:編輯.env文件,并在新的一行增加一個新name=value對。

由于.env文件中包含密碼和其他敏感的賬戶信息, 所以決不能將其添加到 Git 倉庫中,這個文件應該只在存在于本地配置中。使用:echo .env >> .gitignore, 將.env文件列入 git 的忽略文件列表。

需要注意,你部署的生產(chǎn) app 可能使用到與本地開發(fā) app 不同的服務。例如,部署的生產(chǎn) app 可能有一個引用Heroku Postgres數(shù)據(jù)庫的DATABASE_URL配置變量,但你的本地 app可能在.env文件中有一個引用本地安裝的PostgresDATABASE_URL變量。

有時你可能想要在本地使用和 Heroku 環(huán)境相同的配置變量。對于每一個你想要添加到.env文件的配置變量,使用如下命令:

$ heroku config:get CONFIG-VAR-NAME -s >> .env

  • 查看環(huán)境變量

使用heroku config查看 app 的所有配置變量。使用cat .env查看.env文件的內(nèi)容

  • 另一個本地測試工具 Foreman

除了heroku local,原本的foreman也可以使用,但不再提供官方的支持,需要另外安裝。

Heroku Local has replaced Foreman in the Heroku Toolbelt

執(zhí)行 git push 命令部署


部署過程的最后一步是把程序上傳到 Heroku 服務器。在此之前,你要確保所有改動都已經(jīng)提交到本地Git倉庫,然后執(zhí)行git push heroku master把程序上傳到遠程倉庫heroku

上傳代碼,中間遇到一個坑,一開始從本地的rest分支向herokumaster推送,報錯

?  flask_blog git:(rest) git push heroku master
Counting objects: 315, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (309/309), done.
Writing objects: 100% (315/315), 82.51 KiB | 0 bytes/s, done.
Total 315 (delta 190), reused 3 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote:
remote:  !     Push rejected, no Cedar-supported app detected
remote: HINT: This occurs when Heroku cannot detect the buildpack
remote:       to use for this application automatically.
remote: See https://devcenter.heroku.com/articles/buildpacks
remote:
remote: Verifying deploy....
remote:
remote: !   Push rejected to flask-blog-chaonet.
remote:
To https://git.heroku.com/flask-blog-chaonet.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/flask-blog-chaonet.git'

?  flask_blog git:(rest) heroku buildpacks:set heroku/python
Buildpack set. Next release on flask-blog-chaonet will use heroku/python.
Run git push heroku master to create a new release using this buildpack.

?  flask_blog git:(rest) git push heroku master
Counting objects: 315, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (309/309), done.
Writing objects: 100% (315/315), 82.56 KiB | 0 bytes/s, done.
Total 315 (delta 190), reused 3 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Using set buildpack heroku/python
remote:
remote:  !     Push rejected, failed to detect set buildpack heroku/python
remote: More info: https://devcenter.heroku.com/articles/buildpacks#detection-failure
remote:
remote: Verifying deploy....
remote:
remote: !   Push rejected to flask-blog-chaonet.
remote:
To https://git.heroku.com/flask-blog-chaonet.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/flask-blog-chaonet.git'

感覺可能是 分支名稱的問題,嘗試切換到 master,合并分支后再試

?  flask_blog git:(rest) git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

?  flask_blog git:(master) ? git merge rest
Updating 40d4e6e..90872cd
Fast-forward
 .gitignore                                      |   2 +
 Procfile                                        |   1 +
 app.db                                          | Bin 76800 -> 83968 bytes
 app/__init__.py                                 |  67 +++++----
 app/api_1_0/__init__.py                         |   5 +
 app/api_1_0/authentication.py                   |  59 ++++++++
 app/api_1_0/comments.py                         |  79 +++++++++++
 app/api_1_0/decorators.py                       |  21 +++
 app/api_1_0/errors.py                           |  21 +++
 app/api_1_0/posts.py                            |  74 ++++++++++
 app/api_1_0/users.py                            |  75 ++++++++++
 app/auth/__init__.py                            |   5 +
 app/auth/forms.py                               |  65 +++++++++
 app/auth/views.py                               | 196 ++++++++++++++++++++++++++
 app/email.py                                    |  11 ++
 app/exceptions.py                               |   4 +
 app/main/__init__.py                            |  13 ++
 app/main/error.py                               |  12 ++
 app/main/forms.py                               |  69 ++++++++++
 app/main/views.py                               | 401 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 app/models.py                                   |  71 +++++++++-
 app/templates/_comments.html                    |  10 +-
 app/templates/_posts.html                       |  12 +-
 app/templates/{ => auth/email}/confirm.html     |   2 +-
 app/templates/auth/email/confirm.txt            |   6 +
 app/templates/{ => auth/email}/confirmmail.html |   2 +-
 app/templates/{ => auth/email}/confirmmail.txt  |   2 +-
 app/templates/{ => auth}/login.html             |   4 +-
 app/templates/{ => auth}/register.html          |   0
 app/templates/{ => auth}/renew.html             |   0
 app/templates/{ => auth}/unconfirmed.html       |   2 +-
 app/templates/base.html                         |  14 +-
 app/templates/changepassword.html               |   2 +-
 app/templates/changepassword.txt                |   2 +-
 app/templates/confirm.txt                       |   6 -
 app/templates/followers.html                    |   2 +-
 app/templates/{ => main}/index.html             |   6 +-
 app/templates/main/moderate.html                |  16 +++
 app/templates/user.html                         |  14 +-
 app/views.py                                    |   1 -
 app_pro.db                                      |   0
 app_test.db                                     | Bin 0 -> 24576 bytes
 config.py                                       | 130 +++++++++++++----
 requirements.txt                                |  43 ++++++
 run.py                                          | 114 ++++++++++++++-
 test/test_api.py                                |  71 ++++++++++
 test/test_basics.py                             |  24 ++++
 test/test_client.py                             |  86 ++++++++++++
 test/test_selenium.py                           |  90 ++++++++++++
 test/test_user_model.py                         |  45 +++++-
 tmp/coverage/app___init___py.html               | 195 ++++++++++++++++++++++++++
 tmp/coverage/app_api_1_0_authentication_py.html | 209 ++++++++++++++++++++++++++++
 tmp/coverage/app_api_1_0_comments_py.html       | 249 +++++++++++++++++++++++++++++++++
 tmp/coverage/app_api_1_0_decorators_py.html     | 133 ++++++++++++++++++
 tmp/coverage/app_api_1_0_errors_py.html         | 133 ++++++++++++++++++
 tmp/coverage/app_api_1_0_posts_py.html          | 239 ++++++++++++++++++++++++++++++++
 tmp/coverage/app_api_1_0_users_py.html          | 241 ++++++++++++++++++++++++++++++++
 tmp/coverage/app_auth_forms_py.html             | 221 +++++++++++++++++++++++++++++
 tmp/coverage/app_auth_views_py.html             | 483 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tmp/coverage/app_email_py.html                  | 113 +++++++++++++++
 tmp/coverage/app_main___init___py.html          | 117 ++++++++++++++++
 tmp/coverage/app_main_views_py.html             | 823 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tmp/coverage/app_models_py.html                 | 981 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tmp/coverage/coverage_html.js                   | 512 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tmp/coverage/index.html                         | 260 ++++++++++++++++++++++++++++++++++
 tmp/coverage/jquery.debounce.min.js             |   9 ++
 tmp/coverage/jquery.hotkeys.js                  |  99 +++++++++++++
 tmp/coverage/jquery.isonscreen.js               |  53 +++++++
 tmp/coverage/jquery.min.js                      |   4 +
 tmp/coverage/jquery.tablesorter.min.js          |   2 +
 tmp/coverage/keybd_closed.png                   | Bin 0 -> 264 bytes
 tmp/coverage/keybd_open.png                     | Bin 0 -> 267 bytes
 tmp/coverage/status.json                        |   1 +
 tmp/coverage/style.css                          | 326 +++++++++++++++++++++++++++++++++++++++++++
 74 files changed, 7248 insertions(+), 112 deletions(-)
 create mode 100644 Procfile
 create mode 100644 app/api_1_0/__init__.py
 create mode 100644 app/api_1_0/authentication.py
 create mode 100644 app/api_1_0/comments.py
 create mode 100644 app/api_1_0/decorators.py
 create mode 100644 app/api_1_0/errors.py
 create mode 100644 app/api_1_0/posts.py
 create mode 100644 app/api_1_0/users.py
 create mode 100644 app/auth/__init__.py
 create mode 100644 app/auth/forms.py
 create mode 100644 app/auth/views.py
 create mode 100644 app/email.py
 create mode 100644 app/exceptions.py
 create mode 100644 app/main/__init__.py
 create mode 100644 app/main/error.py
 create mode 100644 app/main/forms.py
 create mode 100644 app/main/views.py
 rename app/templates/{ => auth/email}/confirm.html (75%)
 create mode 100644 app/templates/auth/email/confirm.txt
 rename app/templates/{ => auth/email}/confirmmail.html (74%)
 rename app/templates/{ => auth/email}/confirmmail.txt (50%)
 rename app/templates/{ => auth}/login.html (71%)
 rename app/templates/{ => auth}/register.html (100%)
 rename app/templates/{ => auth}/renew.html (100%)
 rename app/templates/{ => auth}/unconfirmed.html (80%)
 delete mode 100644 app/templates/confirm.txt
 rename app/templates/{ => main}/index.html (81%)
 create mode 100644 app/templates/main/moderate.html
 create mode 100644 app_pro.db
 create mode 100644 app_test.db
 create mode 100644 requirements.txt
 create mode 100644 test/test_api.py
 create mode 100644 test/test_basics.py
 create mode 100644 test/test_client.py
 create mode 100644 test/test_selenium.py
 create mode 100644 tmp/coverage/app___init___py.html
 create mode 100644 tmp/coverage/app_api_1_0_authentication_py.html
 create mode 100644 tmp/coverage/app_api_1_0_comments_py.html
 create mode 100644 tmp/coverage/app_api_1_0_decorators_py.html
 create mode 100644 tmp/coverage/app_api_1_0_errors_py.html
 create mode 100644 tmp/coverage/app_api_1_0_posts_py.html
 create mode 100644 tmp/coverage/app_api_1_0_users_py.html
 create mode 100644 tmp/coverage/app_auth_forms_py.html
 create mode 100644 tmp/coverage/app_auth_views_py.html
 create mode 100644 tmp/coverage/app_email_py.html
 create mode 100644 tmp/coverage/app_main___init___py.html
 create mode 100644 tmp/coverage/app_main_views_py.html
 create mode 100644 tmp/coverage/app_models_py.html
 create mode 100644 tmp/coverage/coverage_html.js
 create mode 100644 tmp/coverage/index.html
 create mode 100644 tmp/coverage/jquery.debounce.min.js
 create mode 100644 tmp/coverage/jquery.hotkeys.js
 create mode 100644 tmp/coverage/jquery.isonscreen.js
 create mode 100644 tmp/coverage/jquery.min.js
 create mode 100644 tmp/coverage/jquery.tablesorter.min.js
 create mode 100644 tmp/coverage/keybd_closed.png
 create mode 100644 tmp/coverage/keybd_open.png
 create mode 100644 tmp/coverage/status.json
 create mode 100644 tmp/coverage/style.css

?  flask_blog git:(master) git push heroku master
Counting objects: 491, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (482/482), done.
Writing objects: 100% (491/491), 232.17 KiB | 0 bytes/s, done.
Total 491 (delta 301), reused 2 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Using set buildpack heroku/python
remote: -----> Python app detected
remote: -----> Installing runtime (python-2.7.11)
remote: -----> Installing dependencies with pip
remote:        Collecting alembic==0.8.4 (from -r requirements.txt (line 1))
remote:        Downloading alembic-0.8.4.tar.gz (950kB)
remote:        Collecting bleach==1.4.2 (from -r requirements.txt (line 2))
remote:        Downloading bleach-1.4.2-py2.py3-none-any.whl
remote:        Collecting blinker==1.4 (from -r requirements.txt (line 3))
remote:        Downloading blinker-1.4.tar.gz (111kB)
remote:        Collecting coverage==4.0.3 (from -r requirements.txt (line 4))
remote:        Downloading coverage-4.0.3.tar.gz (354kB)
remote:        Collecting decorator==4.0.6 (from -r requirements.txt (line 5))
remote:        Downloading decorator-4.0.6-py2.py3-none-any.whl
remote:        Collecting dominate==2.1.16 (from -r requirements.txt (line 6))
remote:        Downloading dominate-2.1.16.zip
remote:        Collecting Flask==0.10.1 (from -r requirements.txt (line 7))
remote:        Downloading Flask-0.10.1.tar.gz (544kB)
remote:        Collecting Flask-Bootstrap==3.3.5.7 (from -r requirements.txt (line 8))
remote:        Downloading Flask-Bootstrap-3.3.5.7.tar.gz (451kB)
remote:        Collecting Flask-HTTPAuth==2.7.0 (from -r requirements.txt (line 9))
remote:        Downloading Flask-HTTPAuth-2.7.0.tar.gz
remote:        Collecting Flask-Login==0.3.2 (from -r requirements.txt (line 10))
remote:        Downloading Flask-Login-0.3.2.tar.gz
remote:        Collecting Flask-Mail==0.9.1 (from -r requirements.txt (line 11))
remote:        Downloading Flask-Mail-0.9.1.tar.gz (45kB)
remote:        Collecting Flask-Markdown==0.3 (from -r requirements.txt (line 12))
remote:        Downloading Flask-Markdown-0.3.tar.gz (165kB)
remote:        Collecting Flask-Migrate==1.6.0 (from -r requirements.txt (line 13))
remote:        Downloading Flask-Migrate-1.6.0.tar.gz
remote:        Collecting Flask-Moment==0.5.1 (from -r requirements.txt (line 14))
remote:        Downloading Flask-Moment-0.5.1.tar.gz
remote:        Collecting Flask-PageDown==0.2.1 (from -r requirements.txt (line 15))
remote:        Downloading Flask-PageDown-0.2.1.tar.gz
remote:        Collecting Flask-Script==2.0.5 (from -r requirements.txt (line 16))
remote:        Downloading Flask-Script-2.0.5.tar.gz (42kB)
remote:        Collecting Flask-SQLAlchemy==2.1 (from -r requirements.txt (line 17))
remote:        Downloading Flask-SQLAlchemy-2.1.tar.gz (95kB)
remote:        Collecting Flask-SSLify==0.1.5 (from -r requirements.txt (line 18))
remote:        Downloading Flask-SSLify-0.1.5.tar.gz
remote:        Collecting Flask-WTF==0.12 (from -r requirements.txt (line 19))
remote:        Downloading Flask_WTF-0.12-py2-none-any.whl
remote:        Collecting ForgeryPy==0.1 (from -r requirements.txt (line 20))
remote:        Downloading ForgeryPy-0.1.tar.gz
remote:        Collecting gunicorn==19.4.5 (from -r requirements.txt (line 21))
remote:        Downloading gunicorn-19.4.5-py2.py3-none-any.whl (112kB)
remote:        Collecting html5lib==0.9999999 (from -r requirements.txt (line 22))
remote:        Downloading html5lib-0.9999999.tar.gz (889kB)
remote:        Collecting httpie==0.9.3 (from -r requirements.txt (line 23))
remote:        Downloading httpie-0.9.3-py2.py3-none-any.whl (66kB)
remote:        Collecting itsdangerous==0.24 (from -r requirements.txt (line 24))
remote:        Downloading itsdangerous-0.24.tar.gz (46kB)
remote:        Collecting Jinja2==2.8 (from -r requirements.txt (line 25))
remote:        Downloading Jinja2-2.8-py2.py3-none-any.whl (263kB)
remote:        Collecting Mako==1.0.3 (from -r requirements.txt (line 26))
remote:        Downloading Mako-1.0.3.tar.gz (565kB)
remote:        Collecting Markdown==2.6.5 (from -r requirements.txt (line 27))
remote:        Downloading Markdown-2.6.5.tar.gz (301kB)
remote:        Collecting MarkupSafe==0.23 (from -r requirements.txt (line 28))
remote:        Downloading MarkupSafe-0.23.tar.gz
remote:        Collecting pbr==1.8.1 (from -r requirements.txt (line 29))
remote:        Downloading pbr-1.8.1-py2.py3-none-any.whl (89kB)
remote:        Collecting psycopg2==2.6.1 (from -r requirements.txt (line 30))
remote:        Downloading psycopg2-2.6.1.tar.gz (371kB)
remote:        Collecting Pygments==2.0.2 (from -r requirements.txt (line 31))
remote:        Downloading Pygments-2.0.2-py2-none-any.whl (672kB)
remote:        Collecting python-editor==0.5 (from -r requirements.txt (line 32))
remote:        Downloading python-editor-0.5.tar.gz
remote:        Collecting requests==2.9.1 (from -r requirements.txt (line 33))
remote:        Downloading requests-2.9.1-py2.py3-none-any.whl (501kB)
remote:        Collecting selenium==2.48.0 (from -r requirements.txt (line 34))
remote:        Downloading selenium-2.48.0-py2-none-any.whl (872kB)
remote:        Collecting six==1.10.0 (from -r requirements.txt (line 35))
remote:        Downloading six-1.10.0-py2.py3-none-any.whl
remote:        Collecting SQLAlchemy==1.0.10 (from -r requirements.txt (line 36))
remote:        Downloading SQLAlchemy-1.0.10.tar.gz (4.7MB)
remote:        Collecting sqlalchemy-migrate==0.10.0 (from -r requirements.txt (line 37))
remote:        Downloading sqlalchemy_migrate-0.10.0-py2-none-any.whl (108kB)
remote:        Collecting sqlparse==0.1.18 (from -r requirements.txt (line 38))
remote:        Downloading sqlparse-0.1.18.tar.gz (58kB)
remote:        Collecting Tempita==0.5.2 (from -r requirements.txt (line 39))
remote:        Downloading Tempita-0.5.2.tar.gz
remote:        Collecting visitor==0.1.2 (from -r requirements.txt (line 40))
remote:        Downloading visitor-0.1.2.tar.gz
remote:        Collecting Werkzeug==0.11.2 (from -r requirements.txt (line 41))
remote:        Downloading Werkzeug-0.11.2-py2.py3-none-any.whl (304kB)
remote:        Collecting wheel==0.24.0 (from -r requirements.txt (line 42))
remote:        Downloading wheel-0.24.0-py2.py3-none-any.whl (63kB)
remote:        Collecting WTForms==2.0.2 (from -r requirements.txt (line 43))
remote:        Downloading WTForms-2.0.2-py27-none-any.whl (128kB)
remote:        Installing collected packages: SQLAlchemy, MarkupSafe, Mako, python-editor, alembic, six, html5lib, bleach, blinker, coverage, decorator, dominate, Werkzeug, Jinja2, itsdangerous, Flask, visitor, Flask-Bootstrap, Flask-HTTPAuth, Flask-Login, Flask-Mail, Markdown, Flask-Markdown, Flask-SQLAlchemy, Flask-Script, Flask-Migrate, Flask-Moment, WTForms, Flask-PageDown, Flask-SSLify, Flask-WTF, ForgeryPy, gunicorn, Pygments, requests, httpie, pbr, psycopg2, selenium, sqlparse, Tempita, sqlalchemy-migrate, wheel
remote:        Running setup.py install for SQLAlchemy
remote:        Running setup.py install for MarkupSafe
remote:        Running setup.py install for Mako
remote:        Running setup.py install for python-editor
remote:        Running setup.py install for alembic
remote:        Running setup.py install for html5lib
remote:        Running setup.py install for blinker
remote:        Running setup.py install for coverage
remote:        Running setup.py install for dominate
remote:        Running setup.py install for itsdangerous
remote:        Running setup.py install for Flask
remote:        Running setup.py install for visitor
remote:        Running setup.py install for Flask-Bootstrap
remote:        Running setup.py install for Flask-HTTPAuth
remote:        Running setup.py install for Flask-Login
remote:        Running setup.py install for Flask-Mail
remote:        Running setup.py install for Markdown
remote:        Running setup.py install for Flask-Markdown
remote:        Running setup.py install for Flask-SQLAlchemy
remote:        Running setup.py install for Flask-Script
remote:        Running setup.py install for Flask-Migrate
remote:        Running setup.py install for Flask-Moment
remote:        Running setup.py install for Flask-PageDown
remote:        Running setup.py install for Flask-SSLify
remote:        Running setup.py install for ForgeryPy
remote:        Running setup.py install for psycopg2
remote:        Running setup.py install for sqlparse
remote:        Running setup.py install for Tempita
remote:        Successfully installed Flask-0.10.1 Flask-Bootstrap-3.3.5.7 Flask-HTTPAuth-2.7.0 Flask-Login-0.3.2 Flask-Mail-0.9.1 Flask-Markdown-0.3 Flask-Migrate-1.6.0 Flask-Moment-0.5.1 Flask-PageDown-0.2.1 Flask-SQLAlchemy-2.1 Flask-SSLify-0.1.5 Flask-Script-2.0.5 Flask-WTF-0.12 ForgeryPy-0.1 Jinja2-2.8 Mako-1.0.3 Markdown-2.6.5 MarkupSafe-0.23 Pygments-2.0.2 SQLAlchemy-1.0.10 Tempita-0.5.2 WTForms-2.0.2 Werkzeug-0.11.2 alembic-0.8.4 bleach-1.4.2 blinker-1.4 coverage-4.0.3 decorator-4.0.6 dominate-2.1.16 gunicorn-19.4.5 html5lib-0.9999999 httpie-0.9.3 itsdangerous-0.24 pbr-1.8.1 psycopg2-2.6.1 python-editor-0.5 requests-2.9.1 selenium-2.48.0 six-1.10.0 sqlalchemy-migrate-0.10.0 sqlparse-0.1.18 visitor-0.1.2 wheel-0.24.0
remote:
remote:
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing... done, 44.6MB
remote: -----> Launching...
remote:        Released v7
remote:        https://flask-blog-chaonet.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/flask-blog-chaonet.git
 * [new branch]      master -> master

成功,按照requirements.txt安裝依賴的庫

建立運行環(huán)境數(shù)據(jù)庫

?  flask_blog git:(master) heroku run python run.py deploy
Running python run.py deploy on flask-blog-chaonet... up, run.6723
/app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
  warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> c1b387222189, empty message
INFO  [alembic.runtime.migration] Running upgrade c1b387222189 -> c4a4f802bdf4, empty message
INFO  [alembic.runtime.migration] Running upgrade c4a4f802bdf4 -> 83e0975c0db1, add role permission
INFO  [alembic.runtime.migration] Running upgrade 83e0975c0db1 -> ee9c55ba9b22, add user profile
INFO  [alembic.runtime.migration] Running upgrade ee9c55ba9b22 -> 431d275d6a70, add user.about_me
INFO  [alembic.runtime.migration] Running upgrade 431d275d6a70 -> d6f4efe3ffe1, add User.avatar_hash
INFO  [alembic.runtime.migration] Running upgrade d6f4efe3ffe1 -> ac6e9871c9a4, add Post ,relationship with User
INFO  [alembic.runtime.migration] Running upgrade ac6e9871c9a4 -> 6f219f6bca6e, add Post.on_changed_body, body_html, db.event.listen
INFO  [alembic.runtime.migration] Running upgrade 6f219f6bca6e -> 3aca4362a467, add Follow model, user.followers
                                                                                                                ollowed
INFO  [alembic.runtime.migration] Running upgrade 3aca4362a467 -> e3cfb10aeab6, add comment model

創(chuàng)建并配置好數(shù)據(jù)庫表之后就可以重啟程序了,直接使用下述命令即可:

     $ heroku restart
     Restarting dynos... done

至此,程序就完全部署好了,可通過 https://<appname>.hero-kuapp.com 訪問。

查看日志


不同類型的消息,會通過顏色區(qū)分顯示

?  flask_blog git:(master) heroku logs
...
2016-01-10T09:04:16.778460+00:00 heroku[run.6723]: Awaiting client
2016-01-10T09:04:16.871340+00:00 heroku[run.6723]: Starting process with command `python run.py deploy`
2016-01-10T09:04:17.236929+00:00 heroku[run.6723]: State changed from starting to up
2016-01-10T09:04:20.574974+00:00 heroku[run.6723]: State changed from up to complete
2016-01-10T09:04:20.567984+00:00 heroku[run.6723]: Process exited with status 0
2016-01-10T09:14:49.296965+00:00 heroku[web.1]: State changed from up to starting
2016-01-10T09:14:53.791001+00:00 heroku[web.1]: Starting process with command `gunicorn run:app`
2016-01-10T09:14:54.840605+00:00 heroku[web.1]: Stopping all processes with SIGTERM
2016-01-10T09:14:56.154205+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Starting gunicorn 19.4.5
2016-01-10T09:14:56.230606+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [10] [INFO] Booting worker with pid: 10
2016-01-10T09:14:56.154848+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Listening at: http://0.0.0.0:10268 (3)
2016-01-10T09:14:56.154974+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Using worker: sync
2016-01-10T09:14:56.160120+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [9] [INFO] Booting worker with pid: 9
2016-01-10T09:14:56.476881+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [10] [INFO] Worker exiting (pid: 10)
2016-01-10T09:14:56.547413+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Shutting down: Master
2016-01-10T09:14:56.475915+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [9] [INFO] Worker exiting (pid: 9)
2016-01-10T09:14:56.529060+00:00 app[web.1]: [2016-01-10 09:14:56 +0000] [3] [INFO] Handling signal: term
2016-01-10T09:14:56.954815+00:00 app[web.1]: /app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
2016-01-10T09:14:56.954818+00:00 app[web.1]:   warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')
2016-01-10T09:14:57.283202+00:00 app[web.1]:   warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')
2016-01-10T09:14:57.283198+00:00 app[web.1]: /app/.heroku/python/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
2016-01-10T09:14:57.480937+00:00 heroku[web.1]: State changed from starting to up
2016-01-10T09:14:57.513335+00:00 heroku[web.1]: Process exited with status 0
2016-01-10T09:15:06.569626+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=32f4cf3a-d766-441b-bbe1-0e7052a37209 fwd="107.161.27.197" dyno=web.1 connect=0ms service=291ms status=200 bytes=3417
2016-01-10T09:15:09.079151+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=flask-blog-chaonet.herokuapp.com request_id=4e065440-cb19-420a-834e-8e4d8e4c956c fwd="107.161.27.197" dyno=web.1 connect=1ms service=19ms status=404 bytes=655
2016-01-10T09:15:16.012079+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=ac1e63ac-0133-4cad-adac-66563437c70c fwd="107.161.27.197" dyno=web.1 connect=0ms service=506ms status=200 bytes=3504
2016-01-10T09:15:17.703574+00:00 heroku[router]: at=info method=GET path="/followed" host=flask-blog-chaonet.herokuapp.com request_id=0fc98138-ca6f-4873-8327-4a22f892d432 fwd="107.161.27.197" dyno=web.1 connect=1ms service=13ms status=302 bytes=875
2016-01-10T09:15:18.327896+00:00 heroku[router]: at=info method=GET path="/auth/login?next=%2Ffollowed" host=flask-blog-chaonet.herokuapp.com request_id=8d44ff19-c673-4e61-929e-d6ce89678b3a fwd="107.161.27.197" dyno=web.1 connect=0ms service=25ms status=200 bytes=4071
2016-01-10T09:15:19.085786+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=flask-blog-chaonet.herokuapp.com request_id=d327a6e7-f26b-4514-8813-c2af94dfd639 fwd="107.161.27.197" dyno=web.1 connect=0ms service=3ms status=404 bytes=655
2016-01-10T09:15:20.795897+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=de598303-d092-4647-8758-9e050d089f2e fwd="107.161.27.197" dyno=web.1 connect=2ms service=23ms status=200 bytes=3504
2016-01-10T09:15:22.840818+00:00 heroku[router]: at=info method=GET path="/auth/login" host=flask-blog-chaonet.herokuapp.com request_id=db4a579c-d80b-4205-963e-53d4f8aeb4a3 fwd="107.161.27.197" dyno=web.1 connect=2ms service=9ms status=200 bytes=4014
2016-01-10T09:15:25.834388+00:00 heroku[router]: at=info method=GET path="/auth/register" host=flask-blog-chaonet.herokuapp.com request_id=32a0d112-6dfa-4c8b-bd25-2bf0296add0d fwd="107.161.27.197" dyno=web.1 connect=2ms service=31ms status=200 bytes=4084
2016-01-10T09:15:28.548938+00:00 heroku[router]: at=info method=GET path="/" host=flask-blog-chaonet.herokuapp.com request_id=0f731062-0cfe-4e51-8967-13ab87ef03c5 fwd="107.161.27.197" dyno=web.1 connect=2ms service=15ms status=200 bytes=3504

應用程序維護模式


維護時可以設置顯示維護信息

?  flask_blog git:(master) heroku maintenance -h
Usage: heroku maintenance

display the current maintenance status of app

 -a, --app APP       # app to run command against
 -r, --remote REMOTE # git remote of app to run command against

Additional commands, type "heroku help COMMAND" for more details:

  maintenance:off  #  take the app out of maintenance mode
  maintenance:on   #  put the app into maintenance mode

開啟顯示維護信息

?  flask_blog git:(master) heroku maintenance:on
Enabling maintenance mode for flask-blog-chaonet... done

頁面顯示的內(nèi)容

Application Offline for Maintenance
This application is undergoing maintenance right now. Please check back later.

維護結束后,重新開啟應用,正常訪問

?  flask_blog git:(master) heroku maintenance:off
Disabling maintenance mode for flask-blog-chaonet... done
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容