溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

flask響應(yīng)錯誤的處理及errorhandler的應(yīng)用方式是什么

發(fā)布時間:2022-12-28 09:47:12 來源:億速云 閱讀:110 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“flask響應(yīng)錯誤的處理及errorhandler的應(yīng)用方式是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

    flask響應(yīng)錯誤處理及errorhandler應(yīng)用

    @app.errorhandler(404)
    def page_not_found(error):
        return render_template('404.html'),404

    則當(dāng)互出現(xiàn)請求錯誤時,并不一定需要設(shè)置重定向路由,僅定義一個errorhandler對應(yīng)的錯誤頁面即可

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h2>404</h2>
    <h2>很抱歉!</h2>
    <p>您訪問的頁面不存在</p>
    </body>
    </html>!

    flask響應(yīng)錯誤的處理及errorhandler的應(yīng)用方式是什么

    flask學(xué)習(xí)筆記:錯誤處理

    1. 做好準(zhǔn)備工作

    • 進入項目主目錄

    • 激活虛擬環(huán)境

    2. Flask中的錯誤處理

    登陸賬號,點開編輯資料頁面,試著將用戶名改為一個已經(jīng)存在的用戶名,然后,你會看到屏幕顯示“Internal Server Error”。

    現(xiàn)在,看看命令行終端,你能看到錯誤堆棧跟蹤,堆棧跟蹤在錯誤調(diào)試時非常有用,因為它們顯示該堆棧中的調(diào)用序列,一直到產(chǎn)生錯誤的那行:

    (venv) $ flask run
     * Serving Flask app "microblog"
     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    [2017-09-14 22:40:02,027] ERROR in app: Exception on /edit_profile [POST]
    Traceback (most recent call last):
      File "/home/miguel/microblog/venv/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context
        context)
      File "/home/miguel/microblog/venv/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 470, in do_execute
        cursor.execute(statement, parameters)
    sqlite3.IntegrityError: UNIQUE constraint failed: user.username

    堆棧跟蹤指出bug出在哪,應(yīng)用允許用戶更改用戶名,但是并不會驗證用戶選擇的新用戶名是否與系統(tǒng)中已有的用戶發(fā)生沖突。該錯誤來自SQLAlchemy,它試圖將新用戶名寫入數(shù)據(jù)庫,但由于用戶名字段設(shè)置了 unique=True,所以寫入被拒絕。

    現(xiàn)在默認的錯誤頁面很丑,與整個應(yīng)用的布局不符。

    3. 調(diào)試模式

    在生產(chǎn)服務(wù)器中,上面那樣的處理錯誤的方式很好,如果出現(xiàn)了錯誤,用戶將看到一個籠統(tǒng)的錯誤頁面,而詳細的錯誤詳細輸出到服務(wù)器進程或者日志文件中。

    但當(dāng)你在開發(fā)應(yīng)用時,你可以開啟調(diào)試模式,F(xiàn)lask會在瀏覽器中輸出非常好的調(diào)試器。先關(guān)閉應(yīng)用,設(shè)置以下環(huán)境變量即可激活調(diào)試模式:

    (venv) $ export FLASK_DEBUG=1

    Windows中使用 set 來設(shè)置。

    設(shè)置完 FLASK_DEBUG 后,重啟應(yīng)用,終端輸出與之前看到的就不同了:

    (venv) microblog2 $ flask run
     * Serving Flask app "microblog"
     * Forcing debug mode on
     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
     * Restarting with stat
     * Debugger is active!
     * Debugger PIN: 177-562-960

    現(xiàn)在,再試試讓程序奔潰,看看瀏覽器中的交互式調(diào)試器。

    調(diào)試器允許你展開每個堆棧幀并查看響應(yīng)的源碼,你也可以在任何幀上打開Python提示符并執(zhí)行任何有效的Python表達式,例如檢查變量的值。

    調(diào)試器允許用戶遠程執(zhí)行服務(wù)器中的代碼,因此對于想要滲入應(yīng)用的而已用戶來說有利。作為附加的安全措施,在瀏覽器中允許的調(diào)試器剛開始是鎖定的,在第一次使用時,會要求輸入PIN碼,你可以在flask run命令的輸出中看到。

    另外,調(diào)試模式還有個很重要的特性,就是重新載入(reloader),這是個很有用的開發(fā)特性,如果你在開啟調(diào)試模式時運行 flask run,修改了源文件并保存,應(yīng)用就會自動重新載入。

    4. 自定義錯誤頁面

    Flask提供了一種機制使應(yīng)用可以安裝自己的錯誤頁面,而不是默認的無聊頁面。比如,我們來定義404錯誤頁面和500錯誤頁面,這兩種錯誤是最常見的。定義其他錯誤頁面同理。

    用 @errorhandler 裝飾器可以自定義錯誤管理器。新建 app/errors.py 模塊。

    app/routes.py

    from flask import render_template
    from app import app, db
     
    @app.errorhandler(404)
    def not_found_error(error):
        return render_template('404.html'), 404
     
    @app.errorhandler(500)
    def internal_error(error):
        db.session.rollback()
        return render_template('500.html'), 500

    錯誤函數(shù)的工作方式和視圖函數(shù)類似。這兩個錯誤會返回各自模板的內(nèi)容。注意這兩個函數(shù)都返回了除模板外的第二個值,也就是錯誤代碼。在之前創(chuàng)建的視圖函數(shù)中,我都沒有顯式的定義第二個值,因為默認值是200(代表成功響應(yīng))。而這兩個是錯誤頁面,所以我希望在響應(yīng)時能反映這一點。

    數(shù)據(jù)庫錯誤會調(diào)用500錯誤。本例中的用戶名重名會造成這個錯誤。為了確保數(shù)據(jù)庫事務(wù)錯誤不會干擾模板觸發(fā)的數(shù)據(jù)庫訪問,程序會執(zhí)行事務(wù)回滾。

    下面是404錯誤的模板:

    app/templates/404.html

    {% extends "base.html" %}
     
    {% block content %}
        <h2>File Not Found</h2>
        <p><a href="{{ url_for('index') }}" rel="external nofollow"  rel="external nofollow" >Back</a></p>
    {% endblock %}

    這是500錯誤的:

    app/templates/500.html

    {% extends "base.html" %}
     
    {% block content %}
        <h2>An unexpected error has occurred</h2>
        <p>The administrator has been notified. Sorry for the inconvenience!</p>
        <p><a href="{{ url_for('index') }}" rel="external nofollow"  rel="external nofollow" >Back</a></p>
    {% endblock %}

    兩個模板都繼承自 base.html 模板。

    在 app/errors.py 模塊導(dǎo)入到 __init__.py 文件中應(yīng)用實例的后面。

    app/__init__.py

    # ...
     
    from app import routes, models, errors

    在終端設(shè)置 FLASK_DEBUG=0 ,然后試著再次觸發(fā)用戶名重名錯誤,你就能看到更友好的錯誤頁面了。

    5. 通過郵件發(fā)送錯誤

    Flask提供的錯誤處理機制有個問題,就是沒有提示,只會在終端輸出堆棧跟蹤,開發(fā)時倒是沒事,但如果應(yīng)用部署到了生產(chǎn)服務(wù)器,沒人會盯著輸出看,所以要想個別的辦法。

    第一種解決方案是觸發(fā)錯誤后發(fā)郵件通知管理員,郵件正文包含堆棧跟蹤。

    第一步,將郵件服務(wù)信息添加到配置文件:

    config.py

    class Config(object):
        # ...
        MAIL_SERVER = os.environ.get('MAIL_SERVER')
        MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25)
        MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
        MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
        MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
        ADMINS = ['your-email@example.com']

    郵件配置變量包含服務(wù)器和端口,用于啟用加密連接的布爾值,以及可選的用戶名和密碼。這五個配置變量都從環(huán)境變量中加載。如果環(huán)境中沒有設(shè)置郵件服務(wù)器,我就會禁用郵件錯誤提示。郵件端口也可以在環(huán)境變量中設(shè)置,如果沒有設(shè)置,就用25端口。ADMIN 配置變量代表用于接收錯誤報告的郵箱地址。

    Flask用Python的 logging 包來寫入日志,這個包可用于用郵件發(fā)送日志。我要做的就是添加 SMTPHandler 實例到Flask記錄器對象,也就是 app.logger:

    app/__init__.py

    import logging
    from logging.handlers import SMTPHandler
     
    # ...
     
    if not app.debug:
        if app.config['MAIL_SERVER']:
            auth = None
            if app.config['MAIL_USERNAME'] or app.config['MAIL_PASSWORD']:
                auth = (app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD'])
            secure = None
            if app.config['MAIL_USE_TLS']:
                secure = ()
            mail_handler = SMTPHandler(
                mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']),
                fromaddr='no-reply@' + app.config['MAIL_SERVER'],
                toaddrs=app.config['ADMINS'], subject='Microblog Failure',
                credentials=auth, secure=secure)
            mail_handler.setLevel(logging.ERROR)
            app.logger.addHandler(mail_handler)

    以上程序只在調(diào)試模式為開啟時才會開啟郵件記錄器功能,也就是當(dāng) app.debug 為 True 以及郵件服務(wù)可用時。
    設(shè)置郵件記錄器有些繁瑣,因為必須要處理許多郵件服務(wù)的安全可選項。但實際上,上面的代碼創(chuàng)建了 SMTPHandler 實例。設(shè)置其級別,使其只報告錯誤信息。

    測試此功能的方法有兩種。簡單的這種是使用 Python 中的 SMTP 調(diào)試服務(wù),接收郵件而不是發(fā)送郵件,并將其打印大盤控制臺。再打開一個終端會話并運行以下命令:

    (venv) $ python -m smtpd -n -c DebuggingServer localhost:8025

    設(shè)置 MAIL_SERVER=localhost 和 MAIL_PORT=8025。如果用的是 Linux 或者 Mac OS 系統(tǒng),命令前要加上 sudo 前綴。如果用的是 Windows 系統(tǒng),要以管理員權(quán)限打開終端。此命令需要管理員權(quán)限,1024端口以下是是只有管理員才能使用的端口。或者你也可以改為更高的端口號,比如5025,并將 MAIL_PORT 變量設(shè)置為環(huán)境中選擇的端口,這樣就不需要管理員權(quán)限了。

    第二個終端的SMTP調(diào)試服務(wù)保持運行,在第一個終端環(huán)境中設(shè)置 export MAIL_SERVER=localhost 和 MAIL_PORT=8025(Windows中用set)。由于在調(diào)試模式中應(yīng)用不會發(fā)送郵件,所以將FLASK_DEBUG 變量設(shè)置為 0 或者不用設(shè)置。運行應(yīng)用,再觸發(fā)一次 SQLAlchemy 錯誤,在終端就能看到含有堆棧錯誤的郵件了。

    第二種測試方式是配置真正的郵件服務(wù)。下面是如何使用 Gmail 的郵件服務(wù):

    export MAIL_SERVER=smtp.googlemail.com
    export MAIL_PORT=587
    export MAIL_USE_TLS=1
    export MAIL_USERNAME=<your-gmail-username>
    export MAIL_PASSWORD=<your-gmail-password>

    在 Windows 系統(tǒng)種用 set 而不是 export 。

    6. 記錄到文件

    app/__init__.py

    # ...
    from logging.handlers import RotatingFileHandler
    import os
     
    # ...
     
    if not app.debug:
        # ...
     
        if not os.path.exists('logs'):
            os.mkdir('logs')
        file_handler = RotatingFileHandler('logs/microblog.log', maxBytes=10240,
                                           backupCount=10)
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
        file_handler.setLevel(logging.INFO)
        app.logger.addHandler(file_handler)
     
        app.logger.setLevel(logging.INFO)
        app.logger.info('Microblog startup')

    我將文件名為 microblog.log 的日志文件寫入 logs 文件夾。

    RotatingFileHandler 類確保日志文件不會太大。在本例中我將日志文件的大小限制為 10KB,并且將最后10個日志文件保留為備份。

    logging.Formatter 類為日志消息提供自定義格式。由于這些消息會被記錄到文件,所以格式中包含時間戳,日志級別,消息,日志項起始位置的源文件和行號。

    我將應(yīng)用記錄器和文件記錄器處理器的日志等級都設(shè)置為 INFO。(日志級別按照嚴(yán)重程度分別是:DEBUG,INFO,WARNING,ERROR,CRITICAL)。

    每次服務(wù)器啟動時都會往日志寫入行,當(dāng)這個應(yīng)用在生產(chǎn)服務(wù)器中運行時,能看出服務(wù)器上面時候重啟。

    7.  修復(fù)用戶名重名漏洞

    RegistrationForm 已經(jīng)實現(xiàn)了用戶名驗證,但編輯表單并沒有。

    app/forms.py

    class EditProfileForm(FlaskForm):
        username = StringField('Username', validators=[DataRequired()])
        about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
        submit = SubmitField('Submit')
     
        def __init__(self, original_username, *args, **kwargs):
            super(EditProfileForm, self).__init__(*args, **kwargs)
            self.original_username = original_username
     
        def validate_username(self, username):
            if username.data != self.original_username:
                user = User.query.filter_by(username=self.username.data).first()
                if user is not None:
                    raise ValidationError('Please use a different username.')

    通過自定義驗證方法可以實現(xiàn)這個功能,但這里還有個重載構(gòu)造函數(shù),它接受原始用戶名作為參數(shù)。此用戶名被保存為實例變量,然后用validate_username()方法檢查。如果表單中的用戶名與原始用戶名相同,就不需要檢查數(shù)據(jù)庫中環(huán)有沒有重復(fù)項了。

    將原始用戶名作為參數(shù)加入到視圖函數(shù)。

    app/routes.py

    @app.route('/edit_profile', methods=['GET', 'POST'])
    @login_required
    def edit_profile():
        form = EditProfileForm(current_user.username)
        # ...

    “flask響應(yīng)錯誤的處理及errorhandler的應(yīng)用方式是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

    向AI問一下細節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI